<?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: Assili Salim</title>
    <description>The latest articles on DEV Community by Assili Salim (@assili_salim_e3c07f9954de).</description>
    <link>https://dev.to/assili_salim_e3c07f9954de</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%2F3976311%2F67c79ee9-ba0f-4524-b372-e3e745e4dab4.png</url>
      <title>DEV Community: Assili Salim</title>
      <link>https://dev.to/assili_salim_e3c07f9954de</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/assili_salim_e3c07f9954de"/>
    <language>en</language>
    <item>
      <title>Always-Running AI Agents Need Pre-Call Stop Conditions</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Wed, 08 Jul 2026 21:02:58 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/always-running-ai-agents-need-pre-call-stop-conditions-3pag</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/always-running-ai-agents-need-pre-call-stop-conditions-3pag</guid>
      <description>&lt;p&gt;Claude Cowork can now keep working after you close your laptop.&lt;/p&gt;

&lt;p&gt;WIRED reports that Anthropic expanded Cowork beyond the desktop app, so users do not need an active desktop session to keep tasks running. Users can interact with limited versions through the Claude smartphone app or web browser, and Cowork can continue tasks after the user clocks out.&lt;/p&gt;

&lt;p&gt;That is a useful feature.&lt;/p&gt;

&lt;p&gt;It also creates a runtime engineering problem.&lt;/p&gt;

&lt;p&gt;If agents can run unattended, they need stop conditions before provider calls execute.&lt;/p&gt;

&lt;p&gt;A chatbot waits. An agent continues.&lt;/p&gt;

&lt;p&gt;A chatbot is mostly reactive.&lt;/p&gt;

&lt;p&gt;The user sends a message.&lt;/p&gt;

&lt;p&gt;The model responds.&lt;/p&gt;

&lt;p&gt;The interaction pauses.&lt;/p&gt;

&lt;p&gt;An agent is different.&lt;/p&gt;

&lt;p&gt;It may:&lt;/p&gt;

&lt;p&gt;call a model&lt;br&gt;
call tools&lt;br&gt;
inspect results&lt;br&gt;
add context&lt;br&gt;
retry&lt;br&gt;
call another tool&lt;br&gt;
generate a document&lt;br&gt;
send another provider request&lt;br&gt;
keep going while the user is away&lt;/p&gt;

&lt;p&gt;That means the agent runtime needs controls.&lt;/p&gt;

&lt;p&gt;Not only logs.&lt;/p&gt;

&lt;p&gt;Not only dashboards.&lt;/p&gt;

&lt;p&gt;Controls before execution.&lt;/p&gt;

&lt;p&gt;The naive loop&lt;/p&gt;

&lt;p&gt;A simple agent loop might look like this:&lt;/p&gt;

&lt;p&gt;while (!task.done) {&lt;br&gt;
  const response = await provider.call({&lt;br&gt;
    model: task.model,&lt;br&gt;
    messages: task.messages,&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;task = await applyAgentStep(task, response);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is easy to write.&lt;/p&gt;

&lt;p&gt;It is also unsafe for unattended workflows.&lt;/p&gt;

&lt;p&gt;There is no max-step limit.&lt;/p&gt;

&lt;p&gt;No budget check.&lt;/p&gt;

&lt;p&gt;No retry-storm detection.&lt;/p&gt;

&lt;p&gt;No prompt-loop detection.&lt;/p&gt;

&lt;p&gt;No known-pricing check.&lt;/p&gt;

&lt;p&gt;No no-progress stop.&lt;/p&gt;

&lt;p&gt;If the agent gets stuck, it keeps creating provider calls until something external stops it.&lt;/p&gt;

&lt;p&gt;That “something” might be a provider error, user intervention, an account limit, or a bill.&lt;/p&gt;

&lt;p&gt;None of those are ideal runtime controls.&lt;/p&gt;

&lt;p&gt;Add a pre-call decision&lt;/p&gt;

&lt;p&gt;A safer loop puts a guard before every provider call.&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId: task.id,&lt;br&gt;
  model: task.model,&lt;br&gt;
  messages: task.messages,&lt;br&gt;
  stepCount: task.steps.length,&lt;br&gt;
  retryCount: task.retryCount,&lt;br&gt;
  budgetRemaining: task.budgetRemaining,&lt;br&gt;
  previousPrompts: task.previousPrompts,&lt;br&gt;
  progressState: task.progress,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  return {&lt;br&gt;
    status: "stopped",&lt;br&gt;
    reason: decision.reason,&lt;br&gt;
    error: decision.error,&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const response = await provider.call({&lt;br&gt;
  model: task.model,&lt;br&gt;
  messages: task.messages,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The exact API does not matter.&lt;/p&gt;

&lt;p&gt;The placement matters.&lt;/p&gt;

&lt;p&gt;The runtime checks the call before the provider sees it.&lt;/p&gt;

&lt;p&gt;What should the runtime check?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Known model pricing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the runtime cannot price the model, it cannot enforce a reliable budget.&lt;/p&gt;

&lt;p&gt;if (!pricingCatalog.has(model)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "unknown_model_pricing",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Do not guess inside an unattended loop.&lt;/p&gt;

&lt;p&gt;A typo, fallback, gateway rewrite, or model alias can break cost assumptions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Task budget&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every unattended run should have a task-level budget.&lt;/p&gt;

&lt;p&gt;if (estimatedNextCallCost &amp;gt; budgetRemaining) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "budget_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Monthly dashboards are useful, but they are late.&lt;/p&gt;

&lt;p&gt;A task budget stops the next call before spend is created.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Max steps&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agents need explicit step limits.&lt;/p&gt;

&lt;p&gt;if (stepCount &amp;gt;= maxSteps) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "max_steps_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;A run that cannot finish inside a reasonable number of steps should stop cleanly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retry storms&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Retries are normal.&lt;/p&gt;

&lt;p&gt;Retry storms are not.&lt;/p&gt;

&lt;p&gt;if (retryCount &amp;gt;= maxRetries &amp;amp;&amp;amp; recentErrorsAreSimilar(errors)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "retry_storm_detected",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The goal is not to remove retries.&lt;/p&gt;

&lt;p&gt;The goal is to prevent repeated failure from becoming the workload.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt loops&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agents often get stuck by asking almost the same thing again.&lt;/p&gt;

&lt;p&gt;if (similarToRecentPrompt(currentPrompt, previousPrompts)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "similar_prompt_loop",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This catches a common pattern:&lt;/p&gt;

&lt;p&gt;the agent looks active, but it is not exploring a new path.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No progress&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A run can consume steps while producing no useful movement.&lt;/p&gt;

&lt;p&gt;Track progress signals:&lt;/p&gt;

&lt;p&gt;errors decreasing&lt;br&gt;
files changing meaningfully&lt;br&gt;
tests improving&lt;br&gt;
checklist items completing&lt;br&gt;
retrieved information changing&lt;br&gt;
user-defined success criteria improving&lt;/p&gt;

&lt;p&gt;If progress does not change after several steps, stop.&lt;/p&gt;

&lt;p&gt;if (!madeProgress(recentSteps)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "no_progress",&lt;br&gt;
  };&lt;br&gt;
}&lt;br&gt;
Why this matters more for always-running agents&lt;/p&gt;

&lt;p&gt;When the user is watching, some failures are caught manually.&lt;/p&gt;

&lt;p&gt;When the agent runs overnight, the runtime becomes the first line of control.&lt;/p&gt;

&lt;p&gt;That changes the design requirement.&lt;/p&gt;

&lt;p&gt;An unattended agent needs:&lt;/p&gt;

&lt;p&gt;local budgets&lt;br&gt;
max-step policies&lt;br&gt;
retry budgets&lt;br&gt;
prompt-loop detection&lt;br&gt;
known model pricing&lt;br&gt;
structured stop reasons&lt;/p&gt;

&lt;p&gt;These are not advanced features.&lt;/p&gt;

&lt;p&gt;They are basic operating rules.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;AI CostGuard is the local-first TypeScript/Node.js runtime safety layer I’m building for AI-agent projects.&lt;/p&gt;

&lt;p&gt;It focuses on pre-call protection for:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
runaway agent execution&lt;br&gt;
unknown model pricing&lt;br&gt;
budget overruns&lt;br&gt;
uncontrolled provider calls&lt;br&gt;
invisible AI-agent cost risk&lt;/p&gt;

&lt;p&gt;It is not a billing ledger.&lt;/p&gt;

&lt;p&gt;It is not a hard security boundary.&lt;/p&gt;

&lt;p&gt;It does not replace provider dashboards.&lt;/p&gt;

&lt;p&gt;The goal is to help the runtime decide whether the next provider call should execute.&lt;/p&gt;

&lt;p&gt;Takeaway&lt;/p&gt;

&lt;p&gt;Always-running agents are useful because they remove friction.&lt;/p&gt;

&lt;p&gt;That same lack of friction is the risk.&lt;/p&gt;

&lt;p&gt;If an agent can keep working after the laptop closes, it needs runtime rules for when to stop.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>api</category>
    </item>
    <item>
      <title>Tokenizer Changes Can Break AI-Agent Budget Assumptions</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Sat, 04 Jul 2026 08:41:45 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/tokenizer-changes-can-break-ai-agent-budget-assumptions-1cj9</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/tokenizer-changes-can-break-ai-agent-budget-assumptions-1cj9</guid>
      <description>&lt;p&gt;Claude Sonnet 5 is a good reminder that AI-agent cost control is not only about model pricing.&lt;/p&gt;

&lt;p&gt;Anthropic says Sonnet 5 launches at $2 per million input tokens and $10 per million output tokens through August 31, 2026, then moves to $3 per million input tokens and $15 per million output tokens.&lt;/p&gt;

&lt;p&gt;Vercel’s AI Gateway changelog adds an important implementation detail: Sonnet 5 uses an updated tokenizer, and the same input can map to more tokens.&lt;/p&gt;

&lt;p&gt;That matters if you build agents.&lt;/p&gt;

&lt;p&gt;A model can have attractive pricing and still change your runtime cost assumptions.&lt;/p&gt;

&lt;p&gt;The problem&lt;/p&gt;

&lt;p&gt;Many agent systems estimate cost like this:&lt;/p&gt;

&lt;p&gt;const estimatedCost =&lt;br&gt;
  inputTokens * inputPrice +&lt;br&gt;
  maxOutputTokens * outputPrice;&lt;/p&gt;

&lt;p&gt;That is fine as a start.&lt;/p&gt;

&lt;p&gt;But it assumes the runtime knows:&lt;/p&gt;

&lt;p&gt;which model is being used&lt;br&gt;
how the input is tokenized&lt;br&gt;
the correct input price&lt;br&gt;
the correct output price&lt;br&gt;
how many retries are allowed&lt;br&gt;
how many steps are allowed&lt;br&gt;
whether the agent is making progress&lt;/p&gt;

&lt;p&gt;If any of those assumptions drift, the estimate becomes weaker.&lt;/p&gt;

&lt;p&gt;A tokenizer update is one way this happens.&lt;/p&gt;

&lt;p&gt;The prompt text may be the same.&lt;/p&gt;

&lt;p&gt;The token count may not be.&lt;/p&gt;

&lt;p&gt;Agents amplify small estimation errors&lt;/p&gt;

&lt;p&gt;For a single request, a token-count surprise is usually manageable.&lt;/p&gt;

&lt;p&gt;For an agent, it can compound.&lt;/p&gt;

&lt;p&gt;An agent may:&lt;/p&gt;

&lt;p&gt;call the model&lt;br&gt;
inspect files&lt;br&gt;
add context&lt;br&gt;
run tools&lt;br&gt;
retry&lt;br&gt;
ask a similar prompt&lt;br&gt;
switch models&lt;br&gt;
continue for more steps&lt;/p&gt;

&lt;p&gt;Small cost drift per call becomes bigger across a run.&lt;/p&gt;

&lt;p&gt;Now add parallel agents, fallback paths, or long-context workflows.&lt;/p&gt;

&lt;p&gt;The problem is no longer “What does this model cost?”&lt;/p&gt;

&lt;p&gt;The problem is:&lt;/p&gt;

&lt;p&gt;Should this next provider call be allowed?&lt;/p&gt;

&lt;p&gt;Add a pre-call decision&lt;/p&gt;

&lt;p&gt;Before the provider call, add a guard decision.&lt;/p&gt;

&lt;p&gt;type BeforeCallInput = {&lt;br&gt;
  runId: string;&lt;br&gt;
  model: string;&lt;br&gt;
  prompt: string;&lt;br&gt;
  estimatedInputTokens: number;&lt;br&gt;
  maxOutputTokens: number;&lt;br&gt;
  stepCount: number;&lt;br&gt;
  retryCount: number;&lt;br&gt;
  budgetRemaining: number;&lt;br&gt;
  previousPrompts: string[];&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;type GuardDecision =&lt;br&gt;
  | { allowed: true }&lt;br&gt;
  | {&lt;br&gt;
      allowed: false;&lt;br&gt;
      reason:&lt;br&gt;
        | "unknown_model_pricing"&lt;br&gt;
        | "budget_exceeded"&lt;br&gt;
        | "max_steps_exceeded"&lt;br&gt;
        | "retry_storm"&lt;br&gt;
        | "prompt_loop";&lt;br&gt;
    };&lt;/p&gt;

&lt;p&gt;Then use it before execution:&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId,&lt;br&gt;
  model,&lt;br&gt;
  prompt,&lt;br&gt;
  estimatedInputTokens,&lt;br&gt;
  maxOutputTokens,&lt;br&gt;
  stepCount,&lt;br&gt;
  retryCount,&lt;br&gt;
  budgetRemaining,&lt;br&gt;
  previousPrompts,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  return {&lt;br&gt;
    status: "stopped",&lt;br&gt;
    reason: decision.reason,&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const result = await provider.call({&lt;br&gt;
  model,&lt;br&gt;
  prompt,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The important part is placement.&lt;/p&gt;

&lt;p&gt;The check happens before the provider call.&lt;/p&gt;

&lt;p&gt;Not after the bill.&lt;/p&gt;

&lt;p&gt;Fail closed on unknown pricing&lt;/p&gt;

&lt;p&gt;If the runtime does not know the model price, it cannot enforce a reliable budget.&lt;/p&gt;

&lt;p&gt;if (!pricingCatalog.has(model)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "unknown_model_pricing",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Do not guess.&lt;/p&gt;

&lt;p&gt;A model alias, fallback, gateway rewrite, or typo can break your assumptions.&lt;/p&gt;

&lt;p&gt;Unknown pricing should stop the run before the call executes.&lt;/p&gt;

&lt;p&gt;Recalculate tokens after model migration&lt;/p&gt;

&lt;p&gt;When changing models, do not assume the same prompt has the same token count.&lt;/p&gt;

&lt;p&gt;A basic migration checklist:&lt;/p&gt;

&lt;p&gt;run representative prompts through the new tokenizer&lt;br&gt;
compare input token counts&lt;br&gt;
compare output length behavior&lt;br&gt;
update pricing metadata&lt;br&gt;
retest max-step limits&lt;br&gt;
retest retry behavior&lt;br&gt;
check fallback paths&lt;br&gt;
measure cost per successful task&lt;/p&gt;

&lt;p&gt;Cost per token is useful.&lt;/p&gt;

&lt;p&gt;Cost per successful task is more useful.&lt;/p&gt;

&lt;p&gt;Watch retry and prompt-loop behavior&lt;/p&gt;

&lt;p&gt;A smarter model may finish tasks in fewer steps.&lt;/p&gt;

&lt;p&gt;It may also continue longer because it can pursue more complex plans.&lt;/p&gt;

&lt;p&gt;Your runtime should still stop obvious waste.&lt;/p&gt;

&lt;p&gt;if (stepCount &amp;gt;= maxSteps) {&lt;br&gt;
  return { allowed: false, reason: "max_steps_exceeded" };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;if (retryCount &amp;gt;= maxRetries) {&lt;br&gt;
  return { allowed: false, reason: "retry_storm" };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;if (similarToRecentPrompt(prompt, previousPrompts)) {&lt;br&gt;
  return { allowed: false, reason: "prompt_loop" };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;These checks do not make the model better.&lt;/p&gt;

&lt;p&gt;They make the system safer to operate.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;AI CostGuard is the local-first TypeScript/Node.js runtime safety layer I’m building for AI-agent projects.&lt;/p&gt;

&lt;p&gt;It focuses on pre-call safety checks for:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
runaway execution&lt;br&gt;
unknown model pricing&lt;br&gt;
budget overruns&lt;br&gt;
uncontrolled provider calls&lt;/p&gt;

&lt;p&gt;It is not a billing ledger.&lt;/p&gt;

&lt;p&gt;It is not a hard security boundary.&lt;/p&gt;

&lt;p&gt;It does not replace provider dashboards.&lt;/p&gt;

&lt;p&gt;The goal is to catch obviously risky calls before they execute.&lt;/p&gt;

&lt;p&gt;Takeaway&lt;/p&gt;

&lt;p&gt;Model pricing pages tell you the unit price.&lt;/p&gt;

&lt;p&gt;They do not tell you whether your agent should make the next call.&lt;/p&gt;

&lt;p&gt;Tokenizer changes, fallback models, retries, and prompt loops all affect real runtime cost.&lt;/p&gt;

&lt;p&gt;For AI agents, cost safety belongs before the provider call.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Gateway Routing Helps AI Apps. Agent Runtimes Still Need Pre-Call Guards.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Fri, 03 Jul 2026 07:22:32 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/gateway-routing-helps-ai-apps-agent-runtimes-still-need-pre-call-guards-4i9i</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/gateway-routing-helps-ai-apps-agent-runtimes-still-need-pre-call-guards-4i9i</guid>
      <description>&lt;p&gt;Vercel added routing rules to AI Gateway on July 2.&lt;/p&gt;

&lt;p&gt;Routing rules let teams rewrite or deny model requests at the gateway level. A rewrite rule serves a request for one model using another model. A deny rule blocks a model and returns a 403. Vercel lists use cases like rerouting when a model is down or retired, standardizing on one model, routing an expensive model to a cheaper one, or keeping a team off unapproved models.&lt;/p&gt;

&lt;p&gt;That is useful infrastructure.&lt;/p&gt;

&lt;p&gt;But if you are building AI agents, it is not the whole safety layer.&lt;/p&gt;

&lt;p&gt;A gateway can decide where a request goes.&lt;/p&gt;

&lt;p&gt;Your runtime still needs to decide whether the request should happen.&lt;/p&gt;

&lt;p&gt;The difference&lt;/p&gt;

&lt;p&gt;Gateway routing answers:&lt;/p&gt;

&lt;p&gt;"Which model should serve this request?"&lt;/p&gt;

&lt;p&gt;Runtime guarding answers:&lt;/p&gt;

&lt;p&gt;"Should this request be allowed at all?"&lt;/p&gt;

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

&lt;p&gt;A gateway may rewrite:&lt;/p&gt;

&lt;p&gt;anthropic/claude-opus-4.8 -&amp;gt; anthropic/claude-haiku-4.5&lt;/p&gt;

&lt;p&gt;That can keep traffic moving.&lt;/p&gt;

&lt;p&gt;But the gateway may not know:&lt;/p&gt;

&lt;p&gt;the agent already retried 12 times&lt;br&gt;
the current prompt is nearly identical to previous failed prompts&lt;br&gt;
the run exceeded its task budget&lt;br&gt;
the agent passed its max-step limit&lt;br&gt;
tool calls are happening without progress&lt;br&gt;
the fallback model keeps the loop alive but does not improve the task&lt;/p&gt;

&lt;p&gt;That context usually lives inside the agent runtime.&lt;/p&gt;

&lt;p&gt;A naive agent loop&lt;/p&gt;

&lt;p&gt;Many agent loops start like this:&lt;/p&gt;

&lt;p&gt;while (!task.done) {&lt;br&gt;
  const response = await provider.call({&lt;br&gt;
    model: task.model,&lt;br&gt;
    messages: task.messages,&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;task = await applyAgentStep(task, response);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is simple.&lt;/p&gt;

&lt;p&gt;It is also missing the controls that matter in production.&lt;/p&gt;

&lt;p&gt;There is no budget check.&lt;/p&gt;

&lt;p&gt;No max-step check.&lt;/p&gt;

&lt;p&gt;No retry-storm detection.&lt;/p&gt;

&lt;p&gt;No prompt-loop detection.&lt;/p&gt;

&lt;p&gt;No unknown-pricing block.&lt;/p&gt;

&lt;p&gt;No no-progress stop.&lt;/p&gt;

&lt;p&gt;If a gateway rewrites the model, this loop may keep running.&lt;/p&gt;

&lt;p&gt;That is not always what you want.&lt;/p&gt;

&lt;p&gt;Add a pre-call guard&lt;/p&gt;

&lt;p&gt;A safer pattern puts a local decision before the provider call:&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId: task.id,&lt;br&gt;
  model: task.model,&lt;br&gt;
  messages: task.messages,&lt;br&gt;
  stepCount: task.steps.length,&lt;br&gt;
  retryCount: task.retryCount,&lt;br&gt;
  previousPrompts: task.previousPrompts,&lt;br&gt;
  budgetRemaining: task.budgetRemaining,&lt;br&gt;
  progressState: task.progress,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  return {&lt;br&gt;
    status: "stopped",&lt;br&gt;
    reason: decision.reason,&lt;br&gt;
    error: decision.error,&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const response = await provider.call({&lt;br&gt;
  model: task.model,&lt;br&gt;
  messages: task.messages,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The exact API does not matter.&lt;/p&gt;

&lt;p&gt;The placement matters.&lt;/p&gt;

&lt;p&gt;The guard runs before the provider call.&lt;/p&gt;

&lt;p&gt;What should the runtime check?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Known model pricing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the runtime cannot price the model, it cannot enforce a reliable budget.&lt;/p&gt;

&lt;p&gt;if (!pricingCatalog.has(model)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "unknown_model_pricing",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This matters even more when routing and fallback rules exist.&lt;/p&gt;

&lt;p&gt;A rewritten model still has a cost profile.&lt;/p&gt;

&lt;p&gt;The runtime should know it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Budget remaining&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Task-level budgets are different from account-level limits.&lt;/p&gt;

&lt;p&gt;if (estimatedNextCallCost &amp;gt; budgetRemaining) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "budget_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;A monthly dashboard can show spend later.&lt;/p&gt;

&lt;p&gt;A runtime budget can stop the next call now.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Max steps&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agents should have explicit stopping rules.&lt;/p&gt;

&lt;p&gt;if (stepCount &amp;gt;= maxSteps) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "max_steps_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;A model route can change.&lt;/p&gt;

&lt;p&gt;The step limit should still apply.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retry storms&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Retries are useful.&lt;/p&gt;

&lt;p&gt;Blind retries are not.&lt;/p&gt;

&lt;p&gt;if (retryCount &amp;gt; maxRetries &amp;amp;&amp;amp; recentErrorsAreSimilar(errors)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "retry_storm_detected",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;A fallback model can hide a retry storm by keeping the run alive.&lt;/p&gt;

&lt;p&gt;The runtime should detect the pattern.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt loops&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agents sometimes ask almost the same thing repeatedly.&lt;/p&gt;

&lt;p&gt;if (similarToRecentPrompt(currentPrompt, previousPrompts)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "similar_prompt_loop",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;If the prompt is not changing meaningfully, the model route may not be the main issue.&lt;/p&gt;

&lt;p&gt;The agent may be stuck.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No progress&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A run can be active without improving.&lt;/p&gt;

&lt;p&gt;Useful progress signals include:&lt;/p&gt;

&lt;p&gt;tests passing&lt;br&gt;
errors decreasing&lt;br&gt;
files changing meaningfully&lt;br&gt;
task checklist items completing&lt;br&gt;
user-defined success criteria improving&lt;/p&gt;

&lt;p&gt;If the agent consumes steps without progress, stop.&lt;/p&gt;

&lt;p&gt;Layer the controls&lt;/p&gt;

&lt;p&gt;A good AI-agent architecture can use both gateway policy and runtime guards.&lt;/p&gt;

&lt;p&gt;One possible flow:&lt;/p&gt;

&lt;p&gt;agent wants next call&lt;br&gt;
        ↓&lt;br&gt;
local runtime guard checks run state&lt;br&gt;
        ↓&lt;br&gt;
gateway applies model routing or deny rules&lt;br&gt;
        ↓&lt;br&gt;
provider executes request&lt;br&gt;
        ↓&lt;br&gt;
logs and dashboards record result&lt;/p&gt;

&lt;p&gt;The order matters.&lt;/p&gt;

&lt;p&gt;The runtime has run context.&lt;/p&gt;

&lt;p&gt;The gateway has team-level model policy.&lt;/p&gt;

&lt;p&gt;The provider executes.&lt;/p&gt;

&lt;p&gt;The dashboard explains.&lt;/p&gt;

&lt;p&gt;Do not ask one layer to do all four jobs.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;AI CostGuard is the local-first TypeScript / Node.js runtime safety layer I’m building for this exact class of problem.&lt;/p&gt;

&lt;p&gt;It focuses on pre-call checks for AI-agent projects:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
runaway agent execution&lt;br&gt;
unknown model pricing&lt;br&gt;
budget overruns&lt;br&gt;
uncontrolled provider calls&lt;/p&gt;

&lt;p&gt;It is not a billing ledger.&lt;/p&gt;

&lt;p&gt;It is not a hard security boundary.&lt;/p&gt;

&lt;p&gt;It does not replace provider dashboards or gateway routing.&lt;/p&gt;

&lt;p&gt;The goal is narrower:&lt;/p&gt;

&lt;p&gt;help the agent runtime decide whether the next provider call should execute.&lt;/p&gt;

&lt;p&gt;Takeaway&lt;/p&gt;

&lt;p&gt;Gateway routing is useful.&lt;/p&gt;

&lt;p&gt;It centralizes model policy.&lt;/p&gt;

&lt;p&gt;It helps teams move traffic when models are down, retired, too expensive, or not approved.&lt;/p&gt;

&lt;p&gt;But routing does not replace runtime safety.&lt;/p&gt;

&lt;p&gt;A cheaper fallback can still waste money.&lt;/p&gt;

&lt;p&gt;A policy-approved model can still be part of a prompt loop.&lt;/p&gt;

&lt;p&gt;A valid request can still exceed the task budget.&lt;/p&gt;

&lt;p&gt;For AI agents, the critical question happens before the call:&lt;/p&gt;

&lt;p&gt;Should this request exist?&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7awcer8w5l1lc2ox153g.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7awcer8w5l1lc2ox153g.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Reusable Agent Skills Need Pre-Call Runtime Checks</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Sun, 28 Jun 2026 14:10:34 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/reusable-agent-skills-need-pre-call-runtime-checks-hne</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/reusable-agent-skills-need-pre-call-runtime-checks-hne</guid>
      <description>&lt;p&gt;OpenAI’s recent Codex research includes one detail that matters for developers building agents:&lt;/p&gt;

&lt;p&gt;26.6% of users use skills to share instructions for complex workflows, and more than 10% manage three or more concurrent Codex agents at some point each week.&lt;/p&gt;

&lt;p&gt;That means agent usage is moving from one-off prompts toward reusable workflows.&lt;/p&gt;

&lt;p&gt;That is good.&lt;/p&gt;

&lt;p&gt;It also means failures can become reusable.&lt;/p&gt;

&lt;p&gt;The problem&lt;/p&gt;

&lt;p&gt;A bad prompt can waste one model call.&lt;/p&gt;

&lt;p&gt;A bad agent skill can waste many runs.&lt;/p&gt;

&lt;p&gt;A skill might encode:&lt;/p&gt;

&lt;p&gt;how to retry&lt;br&gt;
how to call tools&lt;br&gt;
how to inspect files&lt;br&gt;
how to recover from errors&lt;br&gt;
how much context to add&lt;br&gt;
when to continue&lt;br&gt;
when to stop&lt;/p&gt;

&lt;p&gt;If those rules are loose, every run inherits the looseness.&lt;/p&gt;

&lt;p&gt;This is the part developers need to treat carefully.&lt;/p&gt;

&lt;p&gt;Reusable agent behavior needs reusable runtime boundaries.&lt;/p&gt;

&lt;p&gt;A naive agent skill&lt;/p&gt;

&lt;p&gt;Imagine a coding-agent skill for fixing failing tests.&lt;/p&gt;

&lt;p&gt;The instruction might be:&lt;/p&gt;

&lt;p&gt;const skill = {&lt;br&gt;
  name: "fix-failing-tests",&lt;br&gt;
  instructions: &lt;code&gt;&lt;br&gt;
    Inspect the failing test.&lt;br&gt;
    Find the relevant files.&lt;br&gt;
    Apply a fix.&lt;br&gt;
    Run the tests again.&lt;br&gt;
    Repeat until the tests pass.&lt;br&gt;
&lt;/code&gt;,&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;This sounds fine.&lt;/p&gt;

&lt;p&gt;But “repeat until the tests pass” is dangerous without runtime limits.&lt;/p&gt;

&lt;p&gt;What if the test failure is environmental?&lt;/p&gt;

&lt;p&gt;What if the agent keeps editing unrelated files?&lt;/p&gt;

&lt;p&gt;What if the prompt barely changes across attempts?&lt;/p&gt;

&lt;p&gt;What if each retry adds more context?&lt;/p&gt;

&lt;p&gt;What if the fallback model has unknown pricing?&lt;/p&gt;

&lt;p&gt;The skill is useful.&lt;/p&gt;

&lt;p&gt;The runtime is under-specified.&lt;/p&gt;

&lt;p&gt;Add a pre-call decision&lt;/p&gt;

&lt;p&gt;Before every provider call, the runtime should decide whether the call is still allowed.&lt;/p&gt;

&lt;p&gt;type BeforeCallInput = {&lt;br&gt;
  runId: string;&lt;br&gt;
  workflowId?: string;&lt;br&gt;
  model: string;&lt;br&gt;
  prompt: string;&lt;br&gt;
  stepCount: number;&lt;br&gt;
  retryCount: number;&lt;br&gt;
  budgetRemaining: number;&lt;br&gt;
  previousPrompts: string[];&lt;br&gt;
  progressState: {&lt;br&gt;
    testsImproved?: boolean;&lt;br&gt;
    errorsChanged?: boolean;&lt;br&gt;
    filesChanged?: boolean;&lt;br&gt;
  };&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;type GuardDecision =&lt;br&gt;
  | { allowed: true }&lt;br&gt;
  | {&lt;br&gt;
      allowed: false;&lt;br&gt;
      reason:&lt;br&gt;
        | "unknown_model_pricing"&lt;br&gt;
        | "budget_exceeded"&lt;br&gt;
        | "max_steps_exceeded"&lt;br&gt;
        | "retry_storm_detected"&lt;br&gt;
        | "similar_prompt_loop"&lt;br&gt;
        | "no_progress";&lt;br&gt;
      error: Error;&lt;br&gt;
    };&lt;/p&gt;

&lt;p&gt;Then use it before the provider call:&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId,&lt;br&gt;
  workflowId,&lt;br&gt;
  model,&lt;br&gt;
  prompt,&lt;br&gt;
  stepCount,&lt;br&gt;
  retryCount,&lt;br&gt;
  budgetRemaining,&lt;br&gt;
  previousPrompts,&lt;br&gt;
  progressState,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  return {&lt;br&gt;
    status: "stopped",&lt;br&gt;
    reason: decision.reason,&lt;br&gt;
    error: decision.error,&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const response = await provider.call({&lt;br&gt;
  model,&lt;br&gt;
  prompt,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The exact API does not matter.&lt;/p&gt;

&lt;p&gt;The placement matters.&lt;/p&gt;

&lt;p&gt;The check happens before the provider call.&lt;/p&gt;

&lt;p&gt;What should the guard check?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Known model pricing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the runtime cannot price the model, it cannot enforce a budget.&lt;/p&gt;

&lt;p&gt;if (!pricingCatalog.has(model)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "unknown_model_pricing",&lt;br&gt;
    error: new Error(&lt;code&gt;Unknown pricing for model: ${model}&lt;/code&gt;),&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Do not guess.&lt;/p&gt;

&lt;p&gt;Fail closed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Budget remaining&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agent workflows should have task-level budgets.&lt;/p&gt;

&lt;p&gt;if (estimatedNextCallCost &amp;gt; budgetRemaining) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "budget_exceeded",&lt;br&gt;
    error: new Error("Agent run budget exceeded"),&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;A small bug fix and a long migration should not share the same budget.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Max steps&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agents need step limits.&lt;/p&gt;

&lt;p&gt;if (stepCount &amp;gt;= maxSteps) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "max_steps_exceeded",&lt;br&gt;
    error: new Error("Maximum agent steps exceeded"),&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is basic production hygiene.&lt;/p&gt;

&lt;p&gt;If a workflow cannot complete inside a reasonable number of steps, it should stop.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retry storms&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Retries are useful.&lt;/p&gt;

&lt;p&gt;Blind retries are expensive.&lt;/p&gt;

&lt;p&gt;if (retryCount &amp;gt;= maxRetries &amp;amp;&amp;amp; recentErrorsAreSimilar(errors)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "retry_storm_detected",&lt;br&gt;
    error: new Error("Retry storm detected"),&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The goal is not to ban retries.&lt;/p&gt;

&lt;p&gt;The goal is to stop repeated failure.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt loops&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A prompt loop happens when the agent keeps asking nearly the same thing.&lt;/p&gt;

&lt;p&gt;if (similarToRecentPrompt(prompt, previousPrompts)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "similar_prompt_loop",&lt;br&gt;
    error: new Error("Similar prompt loop detected"),&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Even a simple similarity check can catch obvious loops.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No progress&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A run can be active and still not improve.&lt;/p&gt;

&lt;p&gt;Track progress signals:&lt;/p&gt;

&lt;p&gt;did tests improve?&lt;br&gt;
did the error change?&lt;br&gt;
did files change meaningfully?&lt;br&gt;
did a checklist item complete?&lt;br&gt;
did the agent reduce uncertainty?&lt;/p&gt;

&lt;p&gt;If several steps pass without progress, stop.&lt;/p&gt;

&lt;p&gt;if (!madeProgress(progressState, recentSteps)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "no_progress",&lt;br&gt;
    error: new Error("Agent run is not making progress"),&lt;br&gt;
  };&lt;br&gt;
}&lt;br&gt;
Why concurrency makes this more important&lt;/p&gt;

&lt;p&gt;OpenAI’s Codex research says more than 10% of users manage three or more concurrent agents at some point each week.&lt;/p&gt;

&lt;p&gt;That changes the risk.&lt;/p&gt;

&lt;p&gt;One agent wasting a few calls is visible.&lt;/p&gt;

&lt;p&gt;Several agents each wasting a few calls can look normal.&lt;/p&gt;

&lt;p&gt;The local loop becomes a global budget problem.&lt;/p&gt;

&lt;p&gt;For parallel workflows, add shared budget checks:&lt;/p&gt;

&lt;p&gt;if (estimatedNextCallCost &amp;gt; workflowBudgetRemaining) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "workflow_budget_exceeded",&lt;br&gt;
    error: new Error("Workflow budget exceeded"),&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Each agent needs its own limit.&lt;/p&gt;

&lt;p&gt;The workflow needs a shared limit.&lt;/p&gt;

&lt;p&gt;Both matter.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;AI CostGuard is the local-first TypeScript / Node.js runtime safety layer I’m building for this problem.&lt;/p&gt;

&lt;p&gt;It focuses on pre-call protection for AI-agent projects:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
runaway execution&lt;br&gt;
unknown model pricing&lt;br&gt;
budget overruns&lt;br&gt;
uncontrolled provider calls&lt;/p&gt;

&lt;p&gt;It is not a billing ledger.&lt;/p&gt;

&lt;p&gt;It is not a hard security boundary.&lt;/p&gt;

&lt;p&gt;It does not replace provider dashboards.&lt;/p&gt;

&lt;p&gt;The goal is to stop obviously risky calls before they execute.&lt;/p&gt;

&lt;p&gt;Takeaway&lt;/p&gt;

&lt;p&gt;Reusable agent skills are a good abstraction.&lt;/p&gt;

&lt;p&gt;But they should not only package instructions.&lt;/p&gt;

&lt;p&gt;They should also inherit runtime policy.&lt;/p&gt;

&lt;p&gt;Before every provider call, ask:&lt;/p&gt;

&lt;p&gt;Should this call still happen?&lt;/p&gt;

&lt;p&gt;That one question catches many expensive agent failures before they become API usage.&lt;/p&gt;

&lt;p&gt;Tags: ai, agents, typescript, devtools&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>api</category>
      <category>llm</category>
    </item>
    <item>
      <title>If AI Agents Run in Parallel, Budget Checks Need to Happen Before Every Provider Call</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Sat, 27 Jun 2026 10:39:23 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/if-ai-agents-run-in-parallel-budget-checks-need-to-happen-before-every-provider-call-47jf</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/if-ai-agents-run-in-parallel-budget-checks-need-to-happen-before-every-provider-call-47jf</guid>
      <description>&lt;p&gt;OpenAI’s latest Codex usage data shows a clear shift from short assistant interactions to longer, delegated agent work.&lt;/p&gt;

&lt;p&gt;By May 2026, 80.6% of sampled individual Codex users had made at least one request estimated to exceed 30 minutes of human work. 70.2% had made one estimated to exceed one hour.&lt;/p&gt;

&lt;p&gt;The more interesting detail:&lt;/p&gt;

&lt;p&gt;By June 2026, the 99th percentile of daily active OpenAI users regularly generated more than 60 hours of Codex agent turns per day, distributed across multiple parallel agents.&lt;/p&gt;

&lt;p&gt;That is the engineering lesson.&lt;/p&gt;

&lt;p&gt;A parallel agent workflow is not a prompt.&lt;/p&gt;

&lt;p&gt;It is a runtime system.&lt;/p&gt;

&lt;p&gt;Runtime systems need budgets.&lt;/p&gt;

&lt;p&gt;The naive version&lt;/p&gt;

&lt;p&gt;A simple agent loop often looks like this:&lt;/p&gt;

&lt;p&gt;while (!task.done) {&lt;br&gt;
  const result = await provider.call({&lt;br&gt;
    model: task.model,&lt;br&gt;
    messages: task.messages,&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;task = await applyAgentStep(task, result);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is easy to write.&lt;/p&gt;

&lt;p&gt;It is also missing the controls that matter in production.&lt;/p&gt;

&lt;p&gt;No max-step limit.&lt;/p&gt;

&lt;p&gt;No budget check.&lt;/p&gt;

&lt;p&gt;No retry-storm detection.&lt;/p&gt;

&lt;p&gt;No prompt-loop detection.&lt;/p&gt;

&lt;p&gt;No unknown-pricing block.&lt;/p&gt;

&lt;p&gt;No no-progress stop.&lt;/p&gt;

&lt;p&gt;Now imagine running many of these in parallel.&lt;/p&gt;

&lt;p&gt;await Promise.all(tasks.map(runAgent));&lt;/p&gt;

&lt;p&gt;This is where the failure mode changes.&lt;/p&gt;

&lt;p&gt;One agent overspending is visible.&lt;/p&gt;

&lt;p&gt;Ten agents each overspending slightly can look like normal usage until the bill or queue pressure shows up.&lt;/p&gt;

&lt;p&gt;The better shape&lt;/p&gt;

&lt;p&gt;Before every provider call, the runtime should make a decision.&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId: task.id,&lt;br&gt;
  workflowId: task.workflowId,&lt;br&gt;
  model: task.model,&lt;br&gt;
  messages: task.messages,&lt;br&gt;
  stepCount: task.steps.length,&lt;br&gt;
  retryCount: task.retryCount,&lt;br&gt;
  budgetRemaining: task.budgetRemaining,&lt;br&gt;
  sharedBudgetRemaining: workflow.budgetRemaining,&lt;br&gt;
  previousPrompts: task.previousPrompts,&lt;br&gt;
  progressState: task.progress,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  return {&lt;br&gt;
    status: "stopped",&lt;br&gt;
    reason: decision.reason,&lt;br&gt;
    error: decision.error,&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const result = await provider.call({&lt;br&gt;
  model: task.model,&lt;br&gt;
  messages: task.messages,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The API shape does not matter.&lt;/p&gt;

&lt;p&gt;The placement matters.&lt;/p&gt;

&lt;p&gt;The guard runs before the provider call.&lt;/p&gt;

&lt;p&gt;That gives the runtime a chance to stop the next unit of spend before it exists.&lt;/p&gt;

&lt;p&gt;What should be checked?&lt;br&gt;
Known model pricing&lt;/p&gt;

&lt;p&gt;If the runtime does not know the model price, it cannot enforce a reliable budget.&lt;/p&gt;

&lt;p&gt;if (!pricingCatalog.has(model)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "unknown_model_pricing",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Do not guess.&lt;/p&gt;

&lt;p&gt;Fail closed.&lt;/p&gt;

&lt;p&gt;Per-run budget&lt;/p&gt;

&lt;p&gt;Each agent run needs its own budget.&lt;/p&gt;

&lt;p&gt;if (estimatedNextCallCost &amp;gt; runBudgetRemaining) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "run_budget_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This stops one confused task from consuming more than it should.&lt;/p&gt;

&lt;p&gt;Shared workflow budget&lt;/p&gt;

&lt;p&gt;Parallel agents also need a shared ceiling.&lt;/p&gt;

&lt;p&gt;if (estimatedNextCallCost &amp;gt; workflowBudgetRemaining) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "workflow_budget_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This matters because parallel waste is harder to notice.&lt;/p&gt;

&lt;p&gt;Each worker may look reasonable locally while the workflow burns too much globally.&lt;/p&gt;

&lt;p&gt;Max-step limit&lt;/p&gt;

&lt;p&gt;Agents should not run forever.&lt;/p&gt;

&lt;p&gt;if (stepCount &amp;gt;= maxSteps) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "max_steps_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Simple controls are often the most valuable.&lt;/p&gt;

&lt;p&gt;Retry-storm detection&lt;/p&gt;

&lt;p&gt;Retries are useful until they become the workload.&lt;/p&gt;

&lt;p&gt;if (retryCount &amp;gt; maxRetries &amp;amp;&amp;amp; recentErrorsAreSimilar(errors)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "retry_storm_detected",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The goal is not to ban retries.&lt;/p&gt;

&lt;p&gt;The goal is to prevent blind retries.&lt;/p&gt;

&lt;p&gt;Prompt-loop detection&lt;/p&gt;

&lt;p&gt;If the current prompt is too similar to earlier failed prompts, the agent may be stuck.&lt;/p&gt;

&lt;p&gt;if (similarToRecentPrompt(currentPrompt, previousPrompts)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "similar_prompt_loop",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This catches a common agent failure:&lt;/p&gt;

&lt;p&gt;the system looks active, but it is asking the same question again.&lt;/p&gt;

&lt;p&gt;No-progress detection&lt;/p&gt;

&lt;p&gt;A run can consume steps without improving the outcome.&lt;/p&gt;

&lt;p&gt;Track progress signals:&lt;/p&gt;

&lt;p&gt;tests passing&lt;br&gt;
errors decreasing&lt;br&gt;
files changing meaningfully&lt;br&gt;
plan items completing&lt;br&gt;
user-defined success criteria improving&lt;/p&gt;

&lt;p&gt;If nothing improves after several steps, stop.&lt;/p&gt;

&lt;p&gt;Why this matters&lt;/p&gt;

&lt;p&gt;OpenAI’s post says agents change the unit of knowledge work from single interactions to delegated, long-horizon tasks. Agents can operate independently for minutes or hours while using tools, interacting with environments, and iterating toward solutions.&lt;/p&gt;

&lt;p&gt;That is exactly why runtime control matters.&lt;/p&gt;

&lt;p&gt;A chatbot can fail and wait for the next user message.&lt;/p&gt;

&lt;p&gt;An agent can fail and continue.&lt;/p&gt;

&lt;p&gt;That continuation is the risk.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;AI CostGuard is the local-first TypeScript / Node.js runtime safety layer I’m building for this problem.&lt;/p&gt;

&lt;p&gt;It is designed to stop agent failure modes before provider calls execute:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
no-progress runs&lt;br&gt;
budget overruns&lt;br&gt;
unknown model pricing&lt;br&gt;
runaway agent behavior&lt;/p&gt;

&lt;p&gt;The core question is:&lt;/p&gt;

&lt;p&gt;Should this next provider call be allowed?&lt;/p&gt;

&lt;p&gt;If no, the runtime should stop with a structured reason.&lt;/p&gt;

&lt;p&gt;Not after the invoice.&lt;/p&gt;

&lt;p&gt;Before the call.&lt;/p&gt;

&lt;p&gt;When agents run for minutes or hours, cost control becomes runtime control.&lt;/p&gt;

&lt;p&gt;When agents run in parallel, cost control becomes coordination.&lt;/p&gt;

&lt;p&gt;Start with one practical rule:&lt;/p&gt;

&lt;p&gt;Never call the provider before asking whether the next call is still allowed.&lt;/p&gt;

&lt;p&gt;Add a pre-call decision object to your agent loop before adding another dashboard.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>api</category>
      <category>agents</category>
    </item>
    <item>
      <title>AI Coding Agents Need Runtime Telemetry Before Commit Telemetry</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Fri, 26 Jun 2026 13:52:33 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/ai-coding-agents-need-runtime-telemetry-before-commit-telemetry-38i2</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/ai-coding-agents-need-runtime-telemetry-before-commit-telemetry-38i2</guid>
      <description>&lt;p&gt;A new arXiv paper published on June 23, 2026 scanned more than 180 million Git repositories to detect traces of AI coding agents in open source. The authors used multiple signals, including configuration-file scanning, commit-message analysis, author-identity matching, and bot-signature lookup.&lt;/p&gt;

&lt;p&gt;The most useful result for developers is the visibility gap.&lt;/p&gt;

&lt;p&gt;In one snapshot, multi-method detection found 850,157 Claude Code commits.&lt;/p&gt;

&lt;p&gt;Bot-account lookup found only 28,154.&lt;/p&gt;

&lt;p&gt;That is 3.3%, or a 30x relative recall gap.&lt;/p&gt;

&lt;p&gt;The paper also reports more than 320,000 commit-attributed agent commits per month across snapshots from December 2024 to April 2026.&lt;/p&gt;

&lt;p&gt;The immediate takeaway:&lt;/p&gt;

&lt;p&gt;AI coding agents are being used heavily.&lt;/p&gt;

&lt;p&gt;The engineering takeaway:&lt;/p&gt;

&lt;p&gt;Single-signal observability is weak.&lt;/p&gt;

&lt;p&gt;Commit telemetry is too late&lt;/p&gt;

&lt;p&gt;A commit is the end of an agent run.&lt;/p&gt;

&lt;p&gt;It does not tell you enough about the run itself.&lt;/p&gt;

&lt;p&gt;A commit may not show:&lt;/p&gt;

&lt;p&gt;how many model calls happened&lt;br&gt;
how many retries happened&lt;br&gt;
whether prompts repeated&lt;br&gt;
whether tools failed&lt;br&gt;
whether the model price was known&lt;br&gt;
whether the run exceeded budget&lt;br&gt;
whether the agent made progress&lt;br&gt;
whether fallback models were used&lt;br&gt;
whether the agent stopped safely&lt;/p&gt;

&lt;p&gt;If you only inspect the repository after the fact, you are observing the artifact.&lt;/p&gt;

&lt;p&gt;You are not observing the execution.&lt;/p&gt;

&lt;p&gt;For agent systems, execution is where many failures happen.&lt;/p&gt;

&lt;p&gt;Agents are loops&lt;/p&gt;

&lt;p&gt;A coding agent is usually some version of this:&lt;/p&gt;

&lt;p&gt;while (!task.done) {&lt;br&gt;
  const response = await model.call(task.context);&lt;/p&gt;

&lt;p&gt;const action = parseAction(response);&lt;/p&gt;

&lt;p&gt;const result = await runTool(action);&lt;/p&gt;

&lt;p&gt;task = updateTask(task, result);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is useful.&lt;/p&gt;

&lt;p&gt;It is also incomplete.&lt;/p&gt;

&lt;p&gt;There is no budget.&lt;/p&gt;

&lt;p&gt;No max-step limit.&lt;/p&gt;

&lt;p&gt;No retry control.&lt;/p&gt;

&lt;p&gt;No prompt-loop detection.&lt;/p&gt;

&lt;p&gt;No known-pricing check.&lt;/p&gt;

&lt;p&gt;No no-progress stop.&lt;/p&gt;

&lt;p&gt;A safer runtime shape puts a decision before the provider call.&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId: task.id,&lt;br&gt;
  model: task.model,&lt;br&gt;
  prompt: task.currentPrompt,&lt;br&gt;
  stepCount: task.steps.length,&lt;br&gt;
  retryCount: task.retryCount,&lt;br&gt;
  previousPrompts: task.previousPrompts,&lt;br&gt;
  budgetRemaining: task.budgetRemaining,&lt;br&gt;
  progressState: task.progress,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  return {&lt;br&gt;
    status: "stopped",&lt;br&gt;
    reason: decision.reason,&lt;br&gt;
    error: decision.error,&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const response = await model.call(task.context);&lt;/p&gt;

&lt;p&gt;The important part is not the exact API.&lt;/p&gt;

&lt;p&gt;The important part is timing.&lt;/p&gt;

&lt;p&gt;The check happens before the provider call.&lt;/p&gt;

&lt;p&gt;That means the runtime can stop unsafe execution before more cost is created.&lt;/p&gt;

&lt;p&gt;What to log before the call&lt;/p&gt;

&lt;p&gt;A useful agent runtime should log decision inputs, not only final outputs.&lt;/p&gt;

&lt;p&gt;For each provider call, consider recording:&lt;/p&gt;

&lt;p&gt;type AgentCallDecision = {&lt;br&gt;
  runId: string;&lt;br&gt;
  model: string;&lt;br&gt;
  modelPriceKnown: boolean;&lt;br&gt;
  stepCount: number;&lt;br&gt;
  maxSteps: number;&lt;br&gt;
  retryCount: number;&lt;br&gt;
  budgetRemaining: number;&lt;br&gt;
  estimatedNextCallCost: number;&lt;br&gt;
  promptSimilarityScore?: number;&lt;br&gt;
  progressScore?: number;&lt;br&gt;
  allowed: boolean;&lt;br&gt;
  stopReason?: string;&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;This gives you data that a commit cannot provide.&lt;/p&gt;

&lt;p&gt;You can now ask:&lt;/p&gt;

&lt;p&gt;Which tasks hit max steps?&lt;/p&gt;

&lt;p&gt;Which runs stopped because pricing was unknown?&lt;/p&gt;

&lt;p&gt;Which prompts repeated?&lt;/p&gt;

&lt;p&gt;Which models caused budget pressure?&lt;/p&gt;

&lt;p&gt;Which agent workflows produced commits only after many failed attempts?&lt;/p&gt;

&lt;p&gt;Which agents consumed budget without progress?&lt;/p&gt;

&lt;p&gt;That is runtime telemetry.&lt;/p&gt;

&lt;p&gt;Guardrails to implement first&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Max-step limits&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agents should not run forever.&lt;/p&gt;

&lt;p&gt;if (stepCount &amp;gt;= maxSteps) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "max_steps_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is basic.&lt;/p&gt;

&lt;p&gt;It is also one of the highest-value controls.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unknown pricing blocks&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the runtime cannot price the model, it cannot enforce a budget.&lt;/p&gt;

&lt;p&gt;if (!pricingCatalog[model]) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "unknown_model_pricing",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Do not guess.&lt;/p&gt;

&lt;p&gt;Fail closed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Budget guards&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Budgets should exist at the task level, not only at the account level.&lt;/p&gt;

&lt;p&gt;if (estimatedNextCallCost &amp;gt; budgetRemaining) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "budget_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;A small refactor and a multi-hour migration should not share the same ceiling.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retry-storm detection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Retries are normal.&lt;/p&gt;

&lt;p&gt;Retry storms are not.&lt;/p&gt;

&lt;p&gt;if (retryCount &amp;gt; maxRetries &amp;amp;&amp;amp; recentErrorsAreSimilar(errors)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "retry_storm_detected",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The goal is not to ban retries.&lt;/p&gt;

&lt;p&gt;The goal is to stop blind repetition.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt-loop detection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the current prompt is almost the same as previous failed prompts, the agent may be stuck.&lt;/p&gt;

&lt;p&gt;if (similarToRecentPrompt(currentPrompt, previousPrompts)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "similar_prompt_loop",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Even a simple similarity check can catch obvious waste.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No-progress detection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A run can be active and still not moving.&lt;/p&gt;

&lt;p&gt;Track progress signals:&lt;/p&gt;

&lt;p&gt;tests passing&lt;br&gt;
errors decreasing&lt;br&gt;
files changing meaningfully&lt;br&gt;
checklist items completing&lt;br&gt;
user-defined success criteria improving&lt;/p&gt;

&lt;p&gt;If those signals do not change after several steps, stop.&lt;/p&gt;

&lt;p&gt;Why this matters now&lt;/p&gt;

&lt;p&gt;GitHub has already said Copilot moved to usage-based billing on June 1, 2026, with usage calculated from token consumption including input, output, and cached tokens. GitHub also described Copilot as moving from an in-editor assistant into an agentic platform capable of long, multi-step coding sessions across repositories.&lt;/p&gt;

&lt;p&gt;That means agent runtime behavior increasingly has direct cost impact.&lt;/p&gt;

&lt;p&gt;A loop is no longer just a UX problem.&lt;/p&gt;

&lt;p&gt;It is a billing problem.&lt;/p&gt;

&lt;p&gt;A retry storm is not just noisy.&lt;/p&gt;

&lt;p&gt;It is spend.&lt;/p&gt;

&lt;p&gt;A prompt loop is not just inefficient.&lt;/p&gt;

&lt;p&gt;It is measurable waste.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;AI CostGuard is the local-first TypeScript / Node.js runtime safety layer I’m building for this problem.&lt;/p&gt;

&lt;p&gt;It focuses on stopping agent failures before provider calls execute:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
no-progress runs&lt;br&gt;
budget overruns&lt;br&gt;
unknown model pricing&lt;br&gt;
runaway agent behavior&lt;/p&gt;

&lt;p&gt;The key design question is simple:&lt;/p&gt;

&lt;p&gt;Should this next provider call be allowed?&lt;/p&gt;

&lt;p&gt;If the answer is no, the runtime should return a structured stop reason before the call happens.&lt;/p&gt;

&lt;p&gt;Takeaway&lt;/p&gt;

&lt;p&gt;The new arXiv paper shows that even detecting AI coding-agent activity in repositories requires multiple signals.&lt;/p&gt;

&lt;p&gt;That lesson applies directly to runtime engineering.&lt;/p&gt;

&lt;p&gt;Do not wait for the commit.&lt;/p&gt;

&lt;p&gt;Do not wait for the dashboard.&lt;/p&gt;

&lt;p&gt;Do not wait for the invoice.&lt;/p&gt;

&lt;p&gt;Instrument the loop.&lt;br&gt;
Add one pre-call decision log to your agent runtime before adding another dashboard.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>api</category>
      <category>llm</category>
    </item>
    <item>
      <title>Usage-Based AI Coding Needs Runtime Budgets, Not Just Billing Dashboards</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Thu, 25 Jun 2026 08:29:05 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/usage-based-ai-coding-needs-runtime-budgets-not-just-billing-dashboards-50d3</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/usage-based-ai-coding-needs-runtime-budgets-not-just-billing-dashboards-50d3</guid>
      <description>&lt;p&gt;The signal&lt;/p&gt;

&lt;p&gt;GitHub reportedly had its “best month ever” in June because demand for AI coding kept growing after Copilot moved to usage-based billing. Business Insider also reported that increased usage has contributed to major outages in 2026 and capacity pressure.&lt;/p&gt;

&lt;p&gt;GitHub’s own billing announcement explains the underlying shift: Copilot moved to AI Credits on June 1, and usage is calculated from token consumption, including input, output, and cached tokens. GitHub also described Copilot as evolving into an agentic platform capable of long, multi-step coding sessions across repositories.&lt;/p&gt;

&lt;p&gt;That matters for engineering.&lt;/p&gt;

&lt;p&gt;A long, multi-step coding session is not a chat message.&lt;/p&gt;

&lt;p&gt;It is a loop.&lt;/p&gt;

&lt;p&gt;And loops need runtime budgets.&lt;/p&gt;

&lt;p&gt;Why this is not just a pricing issue&lt;/p&gt;

&lt;p&gt;Usage-based billing makes one thing very clear:&lt;/p&gt;

&lt;p&gt;runtime behavior has financial consequences.&lt;/p&gt;

&lt;p&gt;A coding agent can spend because it is useful.&lt;/p&gt;

&lt;p&gt;It can also spend because it is stuck.&lt;/p&gt;

&lt;p&gt;The failure mode usually does not look dramatic.&lt;/p&gt;

&lt;p&gt;It looks like this:&lt;/p&gt;

&lt;p&gt;inspect files&lt;br&gt;
call a model&lt;br&gt;
edit code&lt;br&gt;
run tests&lt;br&gt;
fail&lt;br&gt;
add context&lt;br&gt;
call the model again&lt;br&gt;
retry with a similar prompt&lt;br&gt;
switch strategy&lt;br&gt;
call another model&lt;br&gt;
run tests again&lt;br&gt;
keep going&lt;/p&gt;

&lt;p&gt;Every step can look reasonable.&lt;/p&gt;

&lt;p&gt;The whole run can still be waste.&lt;/p&gt;

&lt;p&gt;That is why a billing dashboard is not enough.&lt;/p&gt;

&lt;p&gt;A dashboard tells you what happened after usage exists.&lt;/p&gt;

&lt;p&gt;A runtime budget decides whether the next call should happen.&lt;/p&gt;

&lt;p&gt;A naive agent loop&lt;/p&gt;

&lt;p&gt;A simple coding agent loop might look like this:&lt;/p&gt;

&lt;p&gt;while (!task.done) {&lt;br&gt;
  const response = await provider.call({&lt;br&gt;
    model: task.model,&lt;br&gt;
    messages: task.messages,&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;task = await applyAgentStep(task, response);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is easy to understand.&lt;/p&gt;

&lt;p&gt;It is also dangerous.&lt;/p&gt;

&lt;p&gt;There is no budget.&lt;/p&gt;

&lt;p&gt;No max-step limit.&lt;/p&gt;

&lt;p&gt;No retry-storm detection.&lt;/p&gt;

&lt;p&gt;No prompt-loop detection.&lt;/p&gt;

&lt;p&gt;No known-pricing check.&lt;/p&gt;

&lt;p&gt;No no-progress detection.&lt;/p&gt;

&lt;p&gt;If this loop gets stuck, it keeps spending until something else stops it.&lt;/p&gt;

&lt;p&gt;That “something else” might be a provider limit, a user interruption, an admin cap, or the bill.&lt;/p&gt;

&lt;p&gt;None of those are ideal runtime controls.&lt;/p&gt;

&lt;p&gt;Add a pre-call decision&lt;/p&gt;

&lt;p&gt;A safer pattern puts a guard before the provider call:&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId: task.id,&lt;br&gt;
  model: task.model,&lt;br&gt;
  messages: task.messages,&lt;br&gt;
  stepCount: task.steps.length,&lt;br&gt;
  retryCount: task.retryCount,&lt;br&gt;
  budgetRemaining: task.budgetRemaining,&lt;br&gt;
  previousPrompts: task.previousPrompts,&lt;br&gt;
  progressState: task.progress,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  return {&lt;br&gt;
    status: "stopped",&lt;br&gt;
    reason: decision.reason,&lt;br&gt;
    error: decision.error,&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const response = await provider.call({&lt;br&gt;
  model: task.model,&lt;br&gt;
  messages: task.messages,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The exact API does not matter.&lt;/p&gt;

&lt;p&gt;The placement matters.&lt;/p&gt;

&lt;p&gt;The check happens before the provider call.&lt;/p&gt;

&lt;p&gt;That means the runtime can stop unsafe execution before token usage is created.&lt;/p&gt;

&lt;p&gt;What should the runtime check?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Known model pricing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the runtime does not know the model price, it cannot enforce a reliable budget.&lt;/p&gt;

&lt;p&gt;Do not guess.&lt;/p&gt;

&lt;p&gt;Fail closed.&lt;/p&gt;

&lt;p&gt;if (!pricingCatalog.has(model)) {&lt;br&gt;
  throw new Error(&lt;code&gt;Unknown pricing for model: ${model}&lt;/code&gt;);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;In usage-based billing, model identity is part of the cost contract.&lt;/p&gt;

&lt;p&gt;A typo, alias, fallback, or wrapper mismatch can break assumptions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Task-level budget&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Monthly limits are useful.&lt;/p&gt;

&lt;p&gt;But agent runs also need task-level budgets.&lt;/p&gt;

&lt;p&gt;A code review task should not have the same spend ceiling as a multi-hour migration.&lt;/p&gt;

&lt;p&gt;if (estimatedNextCallCost &amp;gt; budgetRemaining) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "budget_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This lets the agent stop before the next call.&lt;/p&gt;

&lt;p&gt;Not after.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Max-step protection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agent loops need step limits.&lt;/p&gt;

&lt;p&gt;if (stepCount &amp;gt;= maxSteps) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "max_steps_exceeded",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is basic, but important.&lt;/p&gt;

&lt;p&gt;An agent that cannot finish within a reasonable number of steps may be stuck.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retry-storm detection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Retries are useful.&lt;/p&gt;

&lt;p&gt;Retry storms are not.&lt;/p&gt;

&lt;p&gt;if (retryCount &amp;gt;= maxRetries &amp;amp;&amp;amp; lastErrorsAreSimilar(task.errors)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "retry_storm_detected",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The goal is not to remove retries.&lt;/p&gt;

&lt;p&gt;The goal is to prevent blind retries.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt-loop detection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agents sometimes send nearly the same prompt repeatedly.&lt;/p&gt;

&lt;p&gt;Small wording changes can hide the fact that the run is not moving.&lt;/p&gt;

&lt;p&gt;if (isSimilarToRecentPrompt(currentPrompt, previousPrompts)) {&lt;br&gt;
  return {&lt;br&gt;
    allowed: false,&lt;br&gt;
    reason: "similar_prompt_loop",&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Prompt-loop detection is not perfect.&lt;/p&gt;

&lt;p&gt;But even a simple version can catch obvious waste.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No-progress detection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A run can be active and still useless.&lt;/p&gt;

&lt;p&gt;The agent may be editing files, calling tools, and producing logs.&lt;/p&gt;

&lt;p&gt;But the task may not be converging.&lt;/p&gt;

&lt;p&gt;A runtime should track progress signals:&lt;/p&gt;

&lt;p&gt;tests passing&lt;br&gt;
errors decreasing&lt;br&gt;
files changing meaningfully&lt;br&gt;
plan steps completing&lt;br&gt;
final answer getting closer&lt;br&gt;
user-defined success criteria&lt;/p&gt;

&lt;p&gt;If the run consumes steps without progress, stop.&lt;/p&gt;

&lt;p&gt;Why admin caps are not enough&lt;/p&gt;

&lt;p&gt;GitHub’s announcement says admins can set budgets at enterprise, cost center, and user levels, and decide whether to allow additional usage once included credits are exhausted.&lt;/p&gt;

&lt;p&gt;That is useful.&lt;/p&gt;

&lt;p&gt;But admin caps operate at a broad level.&lt;/p&gt;

&lt;p&gt;They do not know why a single agent run is stuck.&lt;/p&gt;

&lt;p&gt;They do not know whether a prompt is repeating.&lt;/p&gt;

&lt;p&gt;They do not know whether this specific task is worth another call.&lt;/p&gt;

&lt;p&gt;That decision belongs closer to the runtime.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;AI CostGuard is the local-first TypeScript runtime layer I’m building for this problem.&lt;/p&gt;

&lt;p&gt;It is designed to stop expensive agent failure modes before provider calls execute:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
no-progress runs&lt;br&gt;
budget overruns&lt;br&gt;
unknown model pricing&lt;br&gt;
runaway agent behavior&lt;/p&gt;

&lt;p&gt;It is not a billing dashboard.&lt;/p&gt;

&lt;p&gt;It is not a cloud control plane.&lt;/p&gt;

&lt;p&gt;It is not a hard security boundary.&lt;/p&gt;

&lt;p&gt;It is a pre-call kill switch for agent cost and loop failures.&lt;/p&gt;

&lt;p&gt;The takeaway&lt;/p&gt;

&lt;p&gt;Usage-based AI coding changes the engineering model.&lt;/p&gt;

&lt;p&gt;You cannot only ask:&lt;/p&gt;

&lt;p&gt;“How much does this tool cost per month?”&lt;/p&gt;

&lt;p&gt;You have to ask:&lt;/p&gt;

&lt;p&gt;“What does my agent do when it gets stuck?”&lt;/p&gt;

&lt;p&gt;For agentic coding, cost control belongs in the runtime.&lt;/p&gt;

&lt;p&gt;Before the provider call.&lt;/p&gt;

&lt;p&gt;Before the bill.&lt;/p&gt;

&lt;p&gt;Before the loop becomes waste.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Claude Had Elevated Errors. Your AI Agent Should Not Turn That Into a Retry Storm.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Wed, 24 Jun 2026 09:29:02 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/claude-had-elevated-errors-your-ai-agent-should-not-turn-that-into-a-retry-storm-5dme</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/claude-had-elevated-errors-your-ai-agent-should-not-turn-that-into-a-retry-storm-5dme</guid>
      <description>&lt;p&gt;The event&lt;/p&gt;

&lt;p&gt;On June 23, Anthropic’s Claude status page listed elevated error rates affecting Claude.ai, resolved at 18:32 UTC. It also showed elevated error rates across multiple models around the same period. On June 24, the status page listed no incidents for the day.&lt;/p&gt;

&lt;p&gt;This kind of incident is easy to frame as a provider problem.&lt;/p&gt;

&lt;p&gt;And it is.&lt;/p&gt;

&lt;p&gt;But for AI-agent developers, it is also a runtime-design problem.&lt;/p&gt;

&lt;p&gt;Because provider instability exposes what your agent does when the model layer becomes unreliable.&lt;/p&gt;

&lt;p&gt;The hidden problem&lt;/p&gt;

&lt;p&gt;A normal chatbot failure is visible.&lt;/p&gt;

&lt;p&gt;The user asks a question.&lt;/p&gt;

&lt;p&gt;The model fails.&lt;/p&gt;

&lt;p&gt;The interface shows an error.&lt;/p&gt;

&lt;p&gt;The user stops.&lt;/p&gt;

&lt;p&gt;Agents are different.&lt;/p&gt;

&lt;p&gt;An agent may be running in a CLI, background job, coding workflow, CI task, support automation, or internal tool.&lt;/p&gt;

&lt;p&gt;It may not stop cleanly.&lt;/p&gt;

&lt;p&gt;It may retry.&lt;/p&gt;

&lt;p&gt;It may call tools again.&lt;/p&gt;

&lt;p&gt;It may add context.&lt;/p&gt;

&lt;p&gt;It may switch models.&lt;/p&gt;

&lt;p&gt;It may repeat the same prompt with minor edits.&lt;/p&gt;

&lt;p&gt;It may continue even though the task is not making progress.&lt;/p&gt;

&lt;p&gt;That turns provider instability into local runtime waste.&lt;/p&gt;

&lt;p&gt;Bad retry logic&lt;/p&gt;

&lt;p&gt;A naive agent loop might look like this:&lt;/p&gt;

&lt;p&gt;for (let attempt = 0; attempt &amp;lt; 3; attempt++) {&lt;br&gt;
  try {&lt;br&gt;
    return await provider.call({&lt;br&gt;
      model,&lt;br&gt;
      messages,&lt;br&gt;
    });&lt;br&gt;
  } catch (err) {&lt;br&gt;
    continue;&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is simple.&lt;/p&gt;

&lt;p&gt;Too simple.&lt;/p&gt;

&lt;p&gt;It does not know whether the provider is degraded.&lt;/p&gt;

&lt;p&gt;It does not know whether the next prompt is similar to the previous one.&lt;/p&gt;

&lt;p&gt;It does not know whether the run has exceeded budget.&lt;/p&gt;

&lt;p&gt;It does not know whether the fallback model is more expensive.&lt;/p&gt;

&lt;p&gt;It does not know whether the agent is making progress.&lt;/p&gt;

&lt;p&gt;For a normal HTTP call, this may be acceptable.&lt;/p&gt;

&lt;p&gt;For an AI agent, it is weak.&lt;/p&gt;

&lt;p&gt;Agents need retry budgets&lt;/p&gt;

&lt;p&gt;A retry count says:&lt;/p&gt;

&lt;p&gt;“Try three times.”&lt;/p&gt;

&lt;p&gt;A retry budget says:&lt;/p&gt;

&lt;p&gt;“Retry only while the run remains safe.”&lt;/p&gt;

&lt;p&gt;That means the runtime should check more than the attempt number.&lt;/p&gt;

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

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId,&lt;br&gt;
  model,&lt;br&gt;
  messages,&lt;br&gt;
  stepCount,&lt;br&gt;
  retryCount,&lt;br&gt;
  providerStatus,&lt;br&gt;
  estimatedInputTokens,&lt;br&gt;
  estimatedOutputTokens,&lt;br&gt;
  budgetRemaining,&lt;br&gt;
  previousPrompts,&lt;br&gt;
  progressState,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  throw decision.error;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const result = await provider.call({&lt;br&gt;
  model,&lt;br&gt;
  messages,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The exact API is not the point.&lt;/p&gt;

&lt;p&gt;The important part is placement.&lt;/p&gt;

&lt;p&gt;The guard runs before the provider call.&lt;/p&gt;

&lt;p&gt;That means it can stop a bad run before more spend happens.&lt;/p&gt;

&lt;p&gt;What should the runtime check?&lt;br&gt;
Budget&lt;/p&gt;

&lt;p&gt;Every agent run should have a task-level budget.&lt;/p&gt;

&lt;p&gt;If the next estimated call would exceed that budget, stop.&lt;/p&gt;

&lt;p&gt;Max steps&lt;/p&gt;

&lt;p&gt;If the agent has already used too many steps, stop.&lt;/p&gt;

&lt;p&gt;A confused agent should not be allowed to run forever.&lt;/p&gt;

&lt;p&gt;Retry storms&lt;/p&gt;

&lt;p&gt;Retries are useful.&lt;/p&gt;

&lt;p&gt;Retry storms are dangerous.&lt;/p&gt;

&lt;p&gt;If the agent keeps hitting similar failures, the runtime should block the next attempt.&lt;/p&gt;

&lt;p&gt;Prompt loops&lt;/p&gt;

&lt;p&gt;If the prompt is almost the same as previous failed attempts, the agent may be stuck.&lt;/p&gt;

&lt;p&gt;Changing a few words is not progress.&lt;/p&gt;

&lt;p&gt;Unknown model pricing&lt;/p&gt;

&lt;p&gt;Fallback logic can be dangerous during provider incidents.&lt;/p&gt;

&lt;p&gt;If the runtime does not know the price of the fallback model, it should fail closed.&lt;/p&gt;

&lt;p&gt;Do not guess inside an autonomous loop.&lt;/p&gt;

&lt;p&gt;No progress&lt;/p&gt;

&lt;p&gt;A run can be active and still useless.&lt;/p&gt;

&lt;p&gt;If the agent is consuming steps and budget without moving closer to a valid result, stop and return a structured error.&lt;/p&gt;

&lt;p&gt;A safer retry shape&lt;/p&gt;

&lt;p&gt;A better agent retry loop treats every provider call as a decision.&lt;/p&gt;

&lt;p&gt;while (!task.done) {&lt;br&gt;
  const decision = guard.beforeCall({&lt;br&gt;
    runId: task.id,&lt;br&gt;
    model: task.model,&lt;br&gt;
    messages: task.messages,&lt;br&gt;
    stepCount: task.steps.length,&lt;br&gt;
    retryCount: task.retryCount,&lt;br&gt;
    budgetRemaining: task.budgetRemaining,&lt;br&gt;
    previousPrompts: task.previousPrompts,&lt;br&gt;
    progressState: task.progress,&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
    return {&lt;br&gt;
      status: "stopped",&lt;br&gt;
      reason: decision.reason,&lt;br&gt;
      error: decision.error,&lt;br&gt;
    };&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;const response = await provider.call({&lt;br&gt;
    model: task.model,&lt;br&gt;
    messages: task.messages,&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;task = updateTaskState(task, response);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This does not make the model smarter.&lt;/p&gt;

&lt;p&gt;It makes the runtime less naive.&lt;/p&gt;

&lt;p&gt;That matters when providers have elevated errors.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;This is the layer I am building with AI CostGuard.&lt;/p&gt;

&lt;p&gt;AI CostGuard is a local-first TypeScript runtime safety layer for AI agents.&lt;/p&gt;

&lt;p&gt;It is designed to stop expensive agent failure modes before provider calls execute:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
no-progress runs&lt;br&gt;
budget overruns&lt;br&gt;
unknown model pricing&lt;br&gt;
runaway agent behavior&lt;/p&gt;

&lt;p&gt;It is not a billing dashboard.&lt;/p&gt;

&lt;p&gt;It is not a hard security boundary.&lt;/p&gt;

&lt;p&gt;It is not a cloud control plane.&lt;/p&gt;

&lt;p&gt;It is a pre-call runtime kill switch for agent cost and loop failures.&lt;/p&gt;

&lt;p&gt;The takeaway&lt;/p&gt;

&lt;p&gt;Every provider will have incidents.&lt;/p&gt;

&lt;p&gt;Claude.&lt;/p&gt;

&lt;p&gt;OpenAI.&lt;/p&gt;

&lt;p&gt;Gemini.&lt;/p&gt;

&lt;p&gt;Any model API.&lt;/p&gt;

&lt;p&gt;That is normal infrastructure reality.&lt;/p&gt;

&lt;p&gt;The important question is what your agent does during the incident.&lt;/p&gt;

&lt;p&gt;If it retries blindly, it can turn provider instability into local cost waste.&lt;/p&gt;

&lt;p&gt;If it has runtime guardrails, it can stop cleanly.&lt;/p&gt;

&lt;p&gt;AI agents need retry budgets.&lt;/p&gt;

&lt;p&gt;Not just retries.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>typescript</category>
    </item>
    <item>
      <title>AI Coding Agents Need Runtime Guardrails, Not Just Human Review</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Tue, 23 Jun 2026 09:07:12 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/ai-coding-agents-need-runtime-guardrails-not-just-human-review-2m7</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/ai-coding-agents-need-runtime-guardrails-not-just-human-review-2m7</guid>
      <description>&lt;p&gt;The recent signal&lt;/p&gt;

&lt;p&gt;Anthropic engineering leader Fiona Fung, who leads teams behind Claude Code and Cowork, said AI coding agents have changed how her teams work.&lt;/p&gt;

&lt;p&gt;The tools help engineers ship more code, but they also make the work lonelier. Developers spend more time working with agents and less time learning directly with other engineers. Fung’s response was to create more intentional collaboration: programming lunches, hackathons, and shared maker time.&lt;/p&gt;

&lt;p&gt;That is an interesting culture story.&lt;/p&gt;

&lt;p&gt;It is also an engineering story.&lt;/p&gt;

&lt;p&gt;Because when developers move from working with humans to operating agents alone, some safety moves out of the room.&lt;/p&gt;

&lt;p&gt;Human collaboration used to catch runtime mistakes&lt;/p&gt;

&lt;p&gt;In normal engineering work, many mistakes are caught informally.&lt;/p&gt;

&lt;p&gt;Someone asks:&lt;/p&gt;

&lt;p&gt;Why are we retrying this again?&lt;/p&gt;

&lt;p&gt;Why does this script have no timeout?&lt;/p&gt;

&lt;p&gt;Why is this touching production?&lt;/p&gt;

&lt;p&gt;Why did the dependency change?&lt;/p&gt;

&lt;p&gt;Why is the task not making progress?&lt;/p&gt;

&lt;p&gt;Why are we calling this API again?&lt;/p&gt;

&lt;p&gt;These are not formal verification systems.&lt;/p&gt;

&lt;p&gt;They are human runtime checks.&lt;/p&gt;

&lt;p&gt;AI coding agents change the workflow.&lt;/p&gt;

&lt;p&gt;A developer gives a task.&lt;/p&gt;

&lt;p&gt;The agent plans.&lt;/p&gt;

&lt;p&gt;The agent edits.&lt;/p&gt;

&lt;p&gt;The agent runs tools.&lt;/p&gt;

&lt;p&gt;The agent calls models.&lt;/p&gt;

&lt;p&gt;The agent retries.&lt;/p&gt;

&lt;p&gt;The agent adds context.&lt;/p&gt;

&lt;p&gt;The agent tries again.&lt;/p&gt;

&lt;p&gt;That loop can be useful.&lt;/p&gt;

&lt;p&gt;It can also continue long after a human teammate would have stopped the run.&lt;/p&gt;

&lt;p&gt;Agents are loops&lt;/p&gt;

&lt;p&gt;A basic model call is simple.&lt;/p&gt;

&lt;p&gt;You send input.&lt;/p&gt;

&lt;p&gt;You get output.&lt;/p&gt;

&lt;p&gt;You inspect the result.&lt;/p&gt;

&lt;p&gt;An agent is different.&lt;/p&gt;

&lt;p&gt;An agent can run through many steps:&lt;/p&gt;

&lt;p&gt;while (!taskDone) {&lt;br&gt;
  const plan = await model.call(context);&lt;br&gt;
  const toolResult = await runTool(plan.tool);&lt;br&gt;
  context = updateContext(context, toolResult);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;That shape is powerful, but incomplete.&lt;/p&gt;

&lt;p&gt;There is no budget.&lt;/p&gt;

&lt;p&gt;No max-step limit.&lt;/p&gt;

&lt;p&gt;No retry-storm detection.&lt;/p&gt;

&lt;p&gt;No prompt-loop detection.&lt;/p&gt;

&lt;p&gt;No unknown-pricing check.&lt;/p&gt;

&lt;p&gt;No no-progress detection.&lt;/p&gt;

&lt;p&gt;A safer version has to ask whether the next provider call should happen at all.&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId,&lt;br&gt;
  model,&lt;br&gt;
  prompt,&lt;br&gt;
  stepCount,&lt;br&gt;
  budget,&lt;br&gt;
  previousPrompts,&lt;br&gt;
  retryState,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  throw decision.error;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const result = await provider.call({&lt;br&gt;
  model,&lt;br&gt;
  prompt,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The important part is placement.&lt;/p&gt;

&lt;p&gt;The guard runs before the provider call.&lt;/p&gt;

&lt;p&gt;Not after.&lt;/p&gt;

&lt;p&gt;Why dashboards are not enough&lt;/p&gt;

&lt;p&gt;Dashboards are useful.&lt;/p&gt;

&lt;p&gt;They show usage.&lt;/p&gt;

&lt;p&gt;They show cost.&lt;/p&gt;

&lt;p&gt;They help debug.&lt;/p&gt;

&lt;p&gt;But they are usually post-execution.&lt;/p&gt;

&lt;p&gt;They answer:&lt;/p&gt;

&lt;p&gt;What happened?&lt;/p&gt;

&lt;p&gt;Agent runtimes need to answer:&lt;/p&gt;

&lt;p&gt;Should this next call happen?&lt;/p&gt;

&lt;p&gt;That question matters because most AI-agent cost failures are not one huge request.&lt;/p&gt;

&lt;p&gt;They are usually sequences of normal-looking calls.&lt;/p&gt;

&lt;p&gt;A retry.&lt;/p&gt;

&lt;p&gt;A similar prompt.&lt;/p&gt;

&lt;p&gt;A tool call.&lt;/p&gt;

&lt;p&gt;Another retry.&lt;/p&gt;

&lt;p&gt;A longer context.&lt;/p&gt;

&lt;p&gt;Another model call.&lt;/p&gt;

&lt;p&gt;Each step may look reasonable.&lt;/p&gt;

&lt;p&gt;The whole run may be waste.&lt;/p&gt;

&lt;p&gt;Useful pre-call checks&lt;/p&gt;

&lt;p&gt;A practical agent runtime should stop execution when basic safety conditions fail.&lt;/p&gt;

&lt;p&gt;Budget guard&lt;/p&gt;

&lt;p&gt;A run should have a task-level budget.&lt;/p&gt;

&lt;p&gt;If the next estimated call crosses that budget, stop before the provider call.&lt;/p&gt;

&lt;p&gt;Max-step protection&lt;/p&gt;

&lt;p&gt;An agent that cannot finish within a reasonable number of steps may be stuck.&lt;/p&gt;

&lt;p&gt;Max-step limits are not fancy.&lt;/p&gt;

&lt;p&gt;They are production safety.&lt;/p&gt;

&lt;p&gt;Retry-storm detection&lt;/p&gt;

&lt;p&gt;Retries are normal.&lt;/p&gt;

&lt;p&gt;Retry storms are not.&lt;/p&gt;

&lt;p&gt;The runtime should detect when the agent keeps repeating failing behavior.&lt;/p&gt;

&lt;p&gt;Similar prompt-loop detection&lt;/p&gt;

&lt;p&gt;If prompts are nearly identical across repeated attempts, the agent may not be exploring new information.&lt;/p&gt;

&lt;p&gt;That should trigger a stop or structured failure.&lt;/p&gt;

&lt;p&gt;Unknown model pricing&lt;/p&gt;

&lt;p&gt;If the runtime does not know the price of the model, it should fail closed.&lt;/p&gt;

&lt;p&gt;Guessing inside an autonomous loop is dangerous.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;This is the layer I am building with AI CostGuard.&lt;/p&gt;

&lt;p&gt;AI CostGuard is a local-first TypeScript runtime safety layer for AI agents.&lt;/p&gt;

&lt;p&gt;It is designed to prevent expensive agent failure modes before provider calls execute:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
no-progress runs&lt;br&gt;
budget overruns&lt;br&gt;
unknown model pricing&lt;br&gt;
runaway agent behavior&lt;/p&gt;

&lt;p&gt;It is developer-focused.&lt;/p&gt;

&lt;p&gt;No SaaS by default.&lt;/p&gt;

&lt;p&gt;No cloud dashboard by default.&lt;/p&gt;

&lt;p&gt;No login.&lt;/p&gt;

&lt;p&gt;No tracking.&lt;/p&gt;

&lt;p&gt;The goal is not to replace provider dashboards.&lt;/p&gt;

&lt;p&gt;The goal is to stop known bad runtime patterns before they become provider spend.&lt;/p&gt;

&lt;p&gt;The takeaway&lt;/p&gt;

&lt;p&gt;AI agents make individual developers more capable.&lt;/p&gt;

&lt;p&gt;They also reduce the human friction between intention and execution.&lt;/p&gt;

&lt;p&gt;That means some safety has to move closer to the runtime.&lt;/p&gt;

&lt;p&gt;If an agent can run alone, it needs limits.&lt;/p&gt;

&lt;p&gt;If it can retry, it needs retry control.&lt;/p&gt;

&lt;p&gt;If it can loop, it needs loop detection.&lt;/p&gt;

&lt;p&gt;If it can call providers, it needs budgets.&lt;/p&gt;

&lt;p&gt;If it can run unattended, it needs a kill switch.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Why Unknown Model Pricing Should Fail Closed in AI-Agent Runtimes</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Mon, 22 Jun 2026 12:40:56 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/why-unknown-model-pricing-should-fail-closed-in-ai-agent-runtimes-4h8h</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/why-unknown-model-pricing-should-fail-closed-in-ai-agent-runtimes-4h8h</guid>
      <description>&lt;p&gt;The problem&lt;/p&gt;

&lt;p&gt;Unknown model pricing looks like a small configuration issue.&lt;/p&gt;

&lt;p&gt;For AI agents, it can become a runtime failure.&lt;/p&gt;

&lt;p&gt;A basic LLM application might send one request and inspect the cost later.&lt;/p&gt;

&lt;p&gt;An AI agent is different.&lt;/p&gt;

&lt;p&gt;An agent can:&lt;/p&gt;

&lt;p&gt;call a model&lt;br&gt;
retry&lt;br&gt;
call tools&lt;br&gt;
add more context&lt;br&gt;
switch models&lt;br&gt;
continue for many steps&lt;br&gt;
fail slowly without crashing&lt;/p&gt;

&lt;p&gt;That means one pricing mistake can multiply across a run.&lt;/p&gt;

&lt;p&gt;If the runtime does not know the model price, it cannot safely enforce a budget.&lt;/p&gt;

&lt;p&gt;That is why unknown model pricing should fail closed before provider API calls execute.&lt;/p&gt;

&lt;p&gt;What “fail closed” means&lt;/p&gt;

&lt;p&gt;Failing closed means the system refuses to continue when it cannot make a safe decision.&lt;/p&gt;

&lt;p&gt;In this case, the decision is:&lt;/p&gt;

&lt;p&gt;Should this next provider call be allowed?&lt;/p&gt;

&lt;p&gt;If the runtime knows the model price, it can estimate cost and compare it against the run budget.&lt;/p&gt;

&lt;p&gt;If the runtime does not know the model price, it should stop.&lt;/p&gt;

&lt;p&gt;Not warn only.&lt;/p&gt;

&lt;p&gt;Not guess.&lt;/p&gt;

&lt;p&gt;Not assume the model is cheap.&lt;/p&gt;

&lt;p&gt;Stop and return a structured error.&lt;/p&gt;

&lt;p&gt;Why this matters more for agents&lt;/p&gt;

&lt;p&gt;Agents are loops.&lt;/p&gt;

&lt;p&gt;That is the core issue.&lt;/p&gt;

&lt;p&gt;A single model call with unknown pricing is one risk.&lt;/p&gt;

&lt;p&gt;An agent loop with unknown pricing is repeated risk.&lt;/p&gt;

&lt;p&gt;The agent might make 10, 20, or 50 calls before anyone notices.&lt;/p&gt;

&lt;p&gt;The failure may come from something simple:&lt;/p&gt;

&lt;p&gt;a typo in the model name&lt;br&gt;
a provider alias that changed&lt;br&gt;
a fallback model that is more expensive&lt;br&gt;
a wrapper passing an unexpected model string&lt;br&gt;
a development config that differs from production&lt;br&gt;
a new model added without pricing metadata&lt;/p&gt;

&lt;p&gt;None of these are dramatic.&lt;/p&gt;

&lt;p&gt;But cost failures usually are not dramatic.&lt;/p&gt;

&lt;p&gt;They are boring runtime mistakes that continue too long.&lt;/p&gt;

&lt;p&gt;Budget guards need reliable inputs&lt;/p&gt;

&lt;p&gt;A budget guard depends on pricing metadata.&lt;/p&gt;

&lt;p&gt;Before a provider call, the runtime might try to answer:&lt;/p&gt;

&lt;p&gt;What model is being used?&lt;br&gt;
What is the estimated input cost?&lt;br&gt;
What is the estimated output cost?&lt;br&gt;
How much budget remains for this run?&lt;br&gt;
Should this call be allowed?&lt;/p&gt;

&lt;p&gt;If pricing is missing, the budget decision becomes weak.&lt;/p&gt;

&lt;p&gt;Here is the rough idea in TypeScript-oriented terms:&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId,&lt;br&gt;
  model,&lt;br&gt;
  inputTokens,&lt;br&gt;
  maxOutputTokens,&lt;br&gt;
  budget,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  throw decision.error;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const result = await provider.call({&lt;br&gt;
  model,&lt;br&gt;
  messages,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The important part is placement.&lt;/p&gt;

&lt;p&gt;The guard runs before the provider call.&lt;/p&gt;

&lt;p&gt;If the model price is unknown, execution stops before spend happens.&lt;/p&gt;

&lt;p&gt;Why a dashboard is too late&lt;/p&gt;

&lt;p&gt;Provider dashboards are useful.&lt;/p&gt;

&lt;p&gt;Billing dashboards are useful.&lt;/p&gt;

&lt;p&gt;Logs and traces are useful.&lt;/p&gt;

&lt;p&gt;But they usually answer the question after execution:&lt;/p&gt;

&lt;p&gt;What happened?&lt;/p&gt;

&lt;p&gt;Runtime guards answer a different question:&lt;/p&gt;

&lt;p&gt;Should this next call happen?&lt;/p&gt;

&lt;p&gt;For AI agents, that second question is critical.&lt;/p&gt;

&lt;p&gt;Once the provider call executes, the cost exists.&lt;/p&gt;

&lt;p&gt;A dashboard might help you understand the mistake.&lt;/p&gt;

&lt;p&gt;A pre-call runtime guard can prevent the mistake from continuing.&lt;/p&gt;

&lt;p&gt;A safer default&lt;/p&gt;

&lt;p&gt;A safe model-pricing rule can be simple:&lt;/p&gt;

&lt;p&gt;if (!pricingCatalog.has(model)) {&lt;br&gt;
  throw new UnknownModelPricingError(model);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is not complex.&lt;/p&gt;

&lt;p&gt;That is the point.&lt;/p&gt;

&lt;p&gt;The runtime should not need advanced reasoning to avoid obvious cost ambiguity.&lt;/p&gt;

&lt;p&gt;If the price is unknown, the call should not proceed.&lt;/p&gt;

&lt;p&gt;The developer can then add pricing metadata, correct the model name, or explicitly change the configuration.&lt;/p&gt;

&lt;p&gt;That is better than silent guessing.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;This is one of the checks I am building into AI CostGuard.&lt;/p&gt;

&lt;p&gt;AI CostGuard is a local-first TypeScript / Node.js runtime safety layer for AI agents.&lt;/p&gt;

&lt;p&gt;It is designed to catch cost and loop failures before provider API calls execute.&lt;/p&gt;

&lt;p&gt;It focuses on:&lt;/p&gt;

&lt;p&gt;retry storm detection&lt;br&gt;
similar prompt loop detection&lt;br&gt;
unknown model pricing blocks&lt;br&gt;
max-step protection&lt;br&gt;
budget guards&lt;br&gt;
middleware and wrappers&lt;br&gt;
structured errors&lt;/p&gt;

&lt;p&gt;It is not a billing ledger.&lt;/p&gt;

&lt;p&gt;It is not a hard security boundary.&lt;/p&gt;

&lt;p&gt;It is not an enterprise firewall.&lt;/p&gt;

&lt;p&gt;It is a pre-call runtime kill switch for AI-agent cost and loop failures.&lt;/p&gt;

&lt;p&gt;The npm package is @salimassili/ai-costguard.&lt;/p&gt;

&lt;p&gt;The takeaway&lt;/p&gt;

&lt;p&gt;AI-agent cost control needs boring rules.&lt;/p&gt;

&lt;p&gt;Know the model.&lt;/p&gt;

&lt;p&gt;Know the price.&lt;/p&gt;

&lt;p&gt;Set the budget.&lt;/p&gt;

&lt;p&gt;Limit the steps.&lt;/p&gt;

&lt;p&gt;Detect loops.&lt;/p&gt;

&lt;p&gt;Stop retry storms.&lt;/p&gt;

&lt;p&gt;Return structured errors.&lt;/p&gt;

&lt;p&gt;Unknown pricing should not be treated as a harmless warning.&lt;/p&gt;

&lt;p&gt;For agents, unknown pricing should fail closed before the provider call executes.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>The AI-Agent Call You Should Block Before It Happens</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Sun, 21 Jun 2026 06:28:35 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/the-ai-agent-call-you-should-block-before-it-happens-4loj</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/the-ai-agent-call-you-should-block-before-it-happens-4loj</guid>
      <description>&lt;p&gt;The most expensive AI-agent call is not always the biggest one.&lt;/p&gt;

&lt;p&gt;Sometimes it is the next one.&lt;/p&gt;

&lt;p&gt;The one after the agent already failed.&lt;/p&gt;

&lt;p&gt;The one after it retried the same operation.&lt;/p&gt;

&lt;p&gt;The one after it called tools without progress.&lt;/p&gt;

&lt;p&gt;The one after the prompt changed slightly but the task did not move forward.&lt;/p&gt;

&lt;p&gt;That provider call may look valid by itself.&lt;/p&gt;

&lt;p&gt;The model name may be correct.&lt;/p&gt;

&lt;p&gt;The prompt may be well-formed.&lt;/p&gt;

&lt;p&gt;The provider may return a normal response.&lt;/p&gt;

&lt;p&gt;But inside the whole agent run, the call should not have happened.&lt;/p&gt;

&lt;p&gt;That is why AI-agent cost control needs to happen before provider API calls execute.&lt;/p&gt;

&lt;p&gt;Agents are loops&lt;/p&gt;

&lt;p&gt;A basic LLM request is simple.&lt;/p&gt;

&lt;p&gt;Input goes in.&lt;/p&gt;

&lt;p&gt;Output comes back.&lt;/p&gt;

&lt;p&gt;You can measure the cost afterward.&lt;/p&gt;

&lt;p&gt;Agents are different.&lt;/p&gt;

&lt;p&gt;An agent may:&lt;/p&gt;

&lt;p&gt;call a model&lt;br&gt;
call a tool&lt;br&gt;
retry&lt;br&gt;
modify the prompt&lt;br&gt;
add more context&lt;br&gt;
switch strategy&lt;br&gt;
call another model&lt;br&gt;
retry again&lt;/p&gt;

&lt;p&gt;That loop is where cost failures appear.&lt;/p&gt;

&lt;p&gt;One step can look reasonable.&lt;/p&gt;

&lt;p&gt;Ten steps can look suspicious.&lt;/p&gt;

&lt;p&gt;Forty steps can become a budget problem.&lt;/p&gt;

&lt;p&gt;The runtime needs to understand the run, not just the individual call.&lt;/p&gt;

&lt;p&gt;The boring failure modes&lt;/p&gt;

&lt;p&gt;Most AI-agent cost failures are not dramatic.&lt;/p&gt;

&lt;p&gt;They are usually boring.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;p&gt;retry storms&lt;br&gt;
similar prompt loops&lt;br&gt;
max-step explosions&lt;br&gt;
unknown model pricing&lt;br&gt;
no-progress runs&lt;br&gt;
budget overruns&lt;/p&gt;

&lt;p&gt;These are not only billing issues.&lt;/p&gt;

&lt;p&gt;They are runtime-control issues.&lt;/p&gt;

&lt;p&gt;A billing dashboard can tell you that the failure happened.&lt;/p&gt;

&lt;p&gt;A runtime guard can stop the next call before it happens.&lt;/p&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;p&gt;A provider success can still be a runtime failure&lt;/p&gt;

&lt;p&gt;This is easy to miss.&lt;/p&gt;

&lt;p&gt;A provider API call can succeed and still be the wrong decision.&lt;/p&gt;

&lt;p&gt;The API can return 200.&lt;/p&gt;

&lt;p&gt;The model can generate text.&lt;/p&gt;

&lt;p&gt;The tool can execute.&lt;/p&gt;

&lt;p&gt;The trace can look clean.&lt;/p&gt;

&lt;p&gt;But the agent may still be stuck.&lt;/p&gt;

&lt;p&gt;This looks simple.&lt;/p&gt;

&lt;p&gt;But there are missing questions.&lt;/p&gt;

&lt;p&gt;How many steps are allowed?&lt;/p&gt;

&lt;p&gt;How much budget can this run spend?&lt;/p&gt;

&lt;p&gt;Are the prompts becoming too similar?&lt;/p&gt;

&lt;p&gt;Is the agent making progress?&lt;/p&gt;

&lt;p&gt;Is the model price known?&lt;/p&gt;

&lt;p&gt;Should the next call be blocked?&lt;/p&gt;

&lt;p&gt;The exact API is not the point.&lt;/p&gt;

&lt;p&gt;The placement is the point.&lt;/p&gt;

&lt;p&gt;The check happens before the provider call.&lt;/p&gt;

&lt;p&gt;What should be checked before the call?&lt;/p&gt;

&lt;p&gt;A useful runtime guard can check simple things.&lt;/p&gt;

&lt;p&gt;Is the model price known?&lt;/p&gt;

&lt;p&gt;If the runtime does not know the price of a model, guessing is risky.&lt;/p&gt;

&lt;p&gt;A typo, alias, fallback, or provider change can break cost assumptions.&lt;/p&gt;

&lt;p&gt;A safer default is to fail closed.&lt;/p&gt;

&lt;p&gt;Has the run exceeded its budget?&lt;/p&gt;

&lt;p&gt;A task-level budget is different from a monthly invoice.&lt;/p&gt;

&lt;p&gt;It asks:&lt;/p&gt;

&lt;p&gt;How much is this specific run allowed to spend?&lt;/p&gt;

&lt;p&gt;Once that limit is reached, the next provider call should not happen.&lt;/p&gt;

&lt;p&gt;Has the agent exceeded max steps?&lt;/p&gt;

&lt;p&gt;Max-step protection is basic but important.&lt;/p&gt;

&lt;p&gt;An agent that cannot finish within a reasonable number of steps may be stuck.&lt;/p&gt;

&lt;p&gt;Letting it run forever is not intelligence.&lt;/p&gt;

&lt;p&gt;It is missing control.&lt;/p&gt;

&lt;p&gt;Is the prompt too similar?&lt;/p&gt;

&lt;p&gt;A similar prompt loop is when the agent keeps asking nearly the same thing with small changes.&lt;/p&gt;

&lt;p&gt;This can burn tokens without producing new information.&lt;/p&gt;

&lt;p&gt;The runtime should detect that pattern.&lt;/p&gt;

&lt;p&gt;Is the agent making progress?&lt;/p&gt;

&lt;p&gt;No-progress runs are expensive because they look active.&lt;/p&gt;

&lt;p&gt;The agent is doing things.&lt;/p&gt;

&lt;p&gt;But the task is not moving forward.&lt;/p&gt;

&lt;p&gt;A guard should be able to stop this before the loop becomes waste.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;This is the layer I am building with AI CostGuard.&lt;/p&gt;

&lt;p&gt;AI CostGuard is a local-first TypeScript / Node.js runtime safety layer for AI agents.&lt;/p&gt;

&lt;p&gt;It is designed to catch cost and loop failures before provider API calls execute.&lt;/p&gt;

&lt;p&gt;It currently focuses on:&lt;/p&gt;

&lt;p&gt;retry storm detection&lt;br&gt;
similar prompt loop detection&lt;br&gt;
unknown model pricing blocks&lt;br&gt;
max-step protection&lt;br&gt;
budget guards&lt;br&gt;
middleware and wrappers&lt;br&gt;
structured errors&lt;/p&gt;

&lt;p&gt;It is not a billing ledger.&lt;/p&gt;

&lt;p&gt;It is not a hard security boundary.&lt;/p&gt;

&lt;p&gt;It is not an enterprise firewall.&lt;/p&gt;

&lt;p&gt;It is a pre-call runtime kill switch for AI-agent cost and loop failures.&lt;/p&gt;

&lt;p&gt;The package is public as @salimassili/ai-costguard.&lt;/p&gt;

&lt;p&gt;The takeaway&lt;/p&gt;

&lt;p&gt;Cheaper tokens help.&lt;/p&gt;

&lt;p&gt;Better routing helps.&lt;/p&gt;

&lt;p&gt;Caching helps.&lt;/p&gt;

&lt;p&gt;Dashboards help.&lt;/p&gt;

&lt;p&gt;But none of them replace runtime limits.&lt;/p&gt;

&lt;p&gt;For AI agents, the important question is not only:&lt;/p&gt;

&lt;p&gt;How much did this model call cost?&lt;/p&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;p&gt;Should this next provider call be allowed?&lt;/p&gt;

&lt;p&gt;That question should be answered before execution.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>typescript</category>
      <category>agents</category>
    </item>
    <item>
      <title>Why AI Agents Need Runtime Budgets Before Provider Calls</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Fri, 19 Jun 2026 08:33:25 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/why-ai-agents-need-runtime-budgets-before-provider-calls-36g8</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/why-ai-agents-need-runtime-budgets-before-provider-calls-36g8</guid>
      <description>&lt;p&gt;The problem&lt;/p&gt;

&lt;p&gt;Most AI cost control happens too late.&lt;/p&gt;

&lt;p&gt;A provider dashboard can tell you what happened after the API calls already executed.&lt;/p&gt;

&lt;p&gt;That is useful.&lt;/p&gt;

&lt;p&gt;But it does not stop a bad agent run while it is happening.&lt;/p&gt;

&lt;p&gt;For basic LLM usage, this may be acceptable. You send one prompt, receive one response, and check the cost later.&lt;/p&gt;

&lt;p&gt;Agents are different.&lt;/p&gt;

&lt;p&gt;An AI agent is not one call.&lt;/p&gt;

&lt;p&gt;It is a loop.&lt;/p&gt;

&lt;p&gt;That loop may include:&lt;/p&gt;

&lt;p&gt;model calls&lt;br&gt;
tool calls&lt;br&gt;
retries&lt;br&gt;
fallback models&lt;br&gt;
growing context&lt;br&gt;
planning steps&lt;br&gt;
validation steps&lt;br&gt;
more retries&lt;/p&gt;

&lt;p&gt;Each step may look reasonable by itself.&lt;/p&gt;

&lt;p&gt;The failure appears across the whole run.&lt;/p&gt;

&lt;p&gt;The expensive failure is usually boring&lt;/p&gt;

&lt;p&gt;Many AI cost failures are not dramatic.&lt;/p&gt;

&lt;p&gt;They are simple runtime failures:&lt;/p&gt;

&lt;p&gt;the agent retries too many times&lt;br&gt;
the prompt changes slightly but not meaningfully&lt;br&gt;
the agent keeps calling tools without progress&lt;br&gt;
the run exceeds a safe step count&lt;br&gt;
the model price is unknown&lt;br&gt;
the workflow crosses a budget limit&lt;/p&gt;

&lt;p&gt;None of these require a complex theory.&lt;/p&gt;

&lt;p&gt;They require boring runtime controls.&lt;/p&gt;

&lt;p&gt;That is the point.&lt;/p&gt;

&lt;p&gt;Production software already has limits everywhere.&lt;/p&gt;

&lt;p&gt;Timeouts.&lt;/p&gt;

&lt;p&gt;Memory limits.&lt;/p&gt;

&lt;p&gt;Rate limits.&lt;/p&gt;

&lt;p&gt;Retry limits.&lt;/p&gt;

&lt;p&gt;Circuit breakers.&lt;/p&gt;

&lt;p&gt;AI-agent runtimes need the same kind of thinking.&lt;/p&gt;

&lt;p&gt;A dashboard is not a guardrail&lt;/p&gt;

&lt;p&gt;A dashboard answers:&lt;/p&gt;

&lt;p&gt;“What happened?”&lt;/p&gt;

&lt;p&gt;A runtime guard answers:&lt;/p&gt;

&lt;p&gt;“Should this next call happen?”&lt;/p&gt;

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

&lt;p&gt;The second one is more important during execution.&lt;/p&gt;

&lt;p&gt;Once the provider call is made, the cost is already real.&lt;/p&gt;

&lt;p&gt;That is why AI-agent cost control should not only happen after the invoice.&lt;/p&gt;

&lt;p&gt;It should happen before provider API calls execute.&lt;/p&gt;

&lt;p&gt;Simple TypeScript-oriented thinking&lt;/p&gt;

&lt;p&gt;Imagine an agent step before a provider call.&lt;/p&gt;

&lt;p&gt;Before sending the request, the runtime can check a few things:&lt;/p&gt;

&lt;p&gt;const decision = guard.beforeCall({&lt;br&gt;
  runId,&lt;br&gt;
  model,&lt;br&gt;
  prompt,&lt;br&gt;
  step,&lt;br&gt;
  estimatedCost,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;if (!decision.allowed) {&lt;br&gt;
  throw decision.error;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const result = await provider.call({&lt;br&gt;
  model,&lt;br&gt;
  prompt,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;The important idea is not the exact API.&lt;/p&gt;

&lt;p&gt;The important idea is the position of the check.&lt;/p&gt;

&lt;p&gt;It happens before the provider call.&lt;/p&gt;

&lt;p&gt;That means the runtime can block dangerous behavior before money is spent.&lt;/p&gt;

&lt;p&gt;Useful checks before the call&lt;/p&gt;

&lt;p&gt;A practical guard layer can ask:&lt;/p&gt;

&lt;p&gt;Is this model price known?&lt;/p&gt;

&lt;p&gt;If not, fail closed.&lt;/p&gt;

&lt;p&gt;Has this run exceeded its budget?&lt;/p&gt;

&lt;p&gt;If yes, stop.&lt;/p&gt;

&lt;p&gt;Has this agent exceeded max steps?&lt;/p&gt;

&lt;p&gt;If yes, stop.&lt;/p&gt;

&lt;p&gt;Is this prompt too similar to previous failed attempts?&lt;/p&gt;

&lt;p&gt;If yes, block the loop.&lt;/p&gt;

&lt;p&gt;Is the agent making no progress?&lt;/p&gt;

&lt;p&gt;If yes, return a structured error.&lt;/p&gt;

&lt;p&gt;These checks do not make the model smarter.&lt;/p&gt;

&lt;p&gt;They make the runtime safer.&lt;/p&gt;

&lt;p&gt;That matters.&lt;/p&gt;

&lt;p&gt;Unknown model pricing should fail closed&lt;/p&gt;

&lt;p&gt;Unknown pricing is easy to underestimate.&lt;/p&gt;

&lt;p&gt;A typo in a model name can break assumptions.&lt;/p&gt;

&lt;p&gt;A provider alias can change.&lt;/p&gt;

&lt;p&gt;A fallback can route to something more expensive.&lt;/p&gt;

&lt;p&gt;A dashboard may show this later.&lt;/p&gt;

&lt;p&gt;A runtime guard can stop it before the call.&lt;/p&gt;

&lt;p&gt;For production agent workflows, unknown pricing should be treated as a risk.&lt;/p&gt;

&lt;p&gt;Failing closed is safer than guessing.&lt;/p&gt;

&lt;p&gt;Max-step limits are production safety&lt;/p&gt;

&lt;p&gt;A max-step limit sounds basic.&lt;/p&gt;

&lt;p&gt;It is basic.&lt;/p&gt;

&lt;p&gt;That is why it belongs in the runtime.&lt;/p&gt;

&lt;p&gt;An agent that cannot finish in a reasonable number of steps may be confused.&lt;/p&gt;

&lt;p&gt;Letting it continue forever is rarely useful.&lt;/p&gt;

&lt;p&gt;A step limit gives the system a clear stopping point.&lt;/p&gt;

&lt;p&gt;It also gives the developer a structured failure to inspect.&lt;/p&gt;

&lt;p&gt;That is better than silent spending.&lt;/p&gt;

&lt;p&gt;Where AI CostGuard fits&lt;/p&gt;

&lt;p&gt;This is the layer I am building with AI CostGuard.&lt;/p&gt;

&lt;p&gt;AI CostGuard is a local-first TypeScript / Node.js runtime safety layer for AI agents.&lt;/p&gt;

&lt;p&gt;It is designed to catch cost and loop failures before provider API calls execute.&lt;/p&gt;

&lt;p&gt;Current checks include:&lt;/p&gt;

&lt;p&gt;retry storm detection&lt;br&gt;
similar prompt loop detection&lt;br&gt;
unknown model pricing blocks&lt;br&gt;
max-step protection&lt;br&gt;
budget guards&lt;br&gt;
middleware and wrapper support&lt;br&gt;
structured errors&lt;/p&gt;

&lt;p&gt;It is not a billing ledger.&lt;/p&gt;

&lt;p&gt;It is not a hard security boundary.&lt;/p&gt;

&lt;p&gt;It is not an enterprise firewall.&lt;/p&gt;

&lt;p&gt;It is a pre-call runtime kill switch for AI-agent cost and loop failures.&lt;/p&gt;

&lt;p&gt;The takeaway&lt;/p&gt;

&lt;p&gt;Cheaper tokens help normal runs.&lt;/p&gt;

&lt;p&gt;Caching helps normal runs.&lt;/p&gt;

&lt;p&gt;Routing helps normal runs.&lt;/p&gt;

&lt;p&gt;But abnormal agent behavior needs runtime limits.&lt;/p&gt;

&lt;p&gt;The key question is not only:&lt;/p&gt;

&lt;p&gt;“How much did this model cost?”&lt;/p&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;p&gt;“Should this next provider call be allowed?”&lt;/p&gt;

&lt;p&gt;For AI agents, that question belongs before execution.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>claude</category>
      <category>chatgpt</category>
    </item>
  </channel>
</rss>
