<?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: Dennis Wong</title>
    <description>The latest articles on DEV Community by Dennis Wong (@dennismcwong).</description>
    <link>https://dev.to/dennismcwong</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3888952%2F949780a7-30d3-4cdb-bf67-23d39eff4d6a.png</url>
      <title>DEV Community: Dennis Wong</title>
      <link>https://dev.to/dennismcwong</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dennismcwong"/>
    <language>en</language>
    <item>
      <title>Your AI Agent Just Spent $3,000. Nobody Told It to Stop.</title>
      <dc:creator>Dennis Wong</dc:creator>
      <pubDate>Mon, 20 Apr 2026 13:57:06 +0000</pubDate>
      <link>https://dev.to/dennismcwong/your-ai-agent-just-spent-3000-nobody-told-it-to-stop-30do</link>
      <guid>https://dev.to/dennismcwong/your-ai-agent-just-spent-3000-nobody-told-it-to-stop-30do</guid>
      <description>&lt;p&gt;&lt;strong&gt;Limenex&lt;/strong&gt; &lt;em&gt;is an open-source, deterministic stateful governance layer for AI agents and agentic systems.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Agentic AI has been the talk of the town. In January 2026, OpenClaw went from zero to 180,000 GitHub stars in two weeks --- the fastest-adopted AI agent in history. It can manage your email, handle payments through Stripe, operate on your filesystem, and take autonomous actions across your digital life.&lt;/p&gt;

&lt;p&gt;Users soon realized it might be a little "too powerful". Within weeks, security researchers found 341 malicious skills in ClawHub, making up 12% of the entire registry. A critical RCE vulnerability (CVE-2026-25253) allowed full instance takeover from a single malicious link. Over 40,000 instances were found exposed on the public internet with no authentication. In China, users who had rushed to install OpenClaw were paying to have it removed after serious and unexpected financial and security consequences. Damages were done, and some were irreversible.&lt;/p&gt;

&lt;p&gt;The incidents show us how capable agentic AI is and what the potential can be. Though capability without governance is a recipe for disaster --- as we have seen with the OpenClaw fiasco.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;The industry knows the problem. Progress has been made, but gaps remain.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt-level enforcement.&lt;/strong&gt; Claude has &lt;code&gt;CLAUDE.md&lt;/code&gt;. OpenAI has instruction hierarchy. Both pin rules in the model's context. This approach is vulnerable to prompt injection and degrades in effectiveness as the context window grows. The UK's National Cyber Security Centre puts it plainly --- LLMs are "inherently confusable deputies."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code-level governance.&lt;/strong&gt; LangChain offers middleware that can gate tool calls before execution. Microsoft's Agent Governance Toolkit is a dedicated policy engine that evaluates function parameters at runtime. Both operate outside the token stream, so prompt injection can't bypass them. But both are stateless by design: each call is evaluated in isolation with no memory of previous actions. This leaves a practical gap --- they can block a $500 charge, but they wouldn't catch a 50th $10 charge.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;How Limenex approaches the problem&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Limenex is an open-source, deterministic governance layer for AI agents. The core philosophy is intent-execution separation: the model decides what it &lt;em&gt;wants&lt;/em&gt; to do, but a policy engine that sits entirely outside the model determines whether it's &lt;em&gt;allowed&lt;/em&gt; to. AI agents are like employees at your organisation --- they can think and plan freely, but policies draw the line between what they can execute unilaterally and what requires sign-off. What actions are allowed, what requires human approval, and what is never permitted --- defined in config, not in a prompt.&lt;/p&gt;

&lt;p&gt;Six core design principles guide our architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Govern actions, not intent.&lt;/strong&gt; Limenex operates on the skill call itself --- the skill name, the parameters, the values. A prompt injection can manipulate what an agent intends to do. It can't change the fact that &lt;code&gt;amount_usd=600&lt;/code&gt; gets evaluated against a policy before the executor fires.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills, not functions.&lt;/strong&gt; Not every agent action needs governance --- only the ones that carry real risk. A skill is a tightly-scoped, vendor-agnostic wrapper around a single consequential action: charging a payment, deleting a file, sending a message. Skills are named after what they do, not which SDK executes it. &lt;code&gt;finance.charge&lt;/code&gt; is the skill --- Stripe, Square, or Braintree is just the executor you inject. Limenex governs whether it runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stateful by default.&lt;/strong&gt; The engine natively supports cumulative state. When a new action comes in, it projects whether executing it would breach a limit defined in your policies --- before it executes. A stateful policy like "block if cumulative spend exceeds $100" doesn't require custom logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three verdicts.&lt;/strong&gt; Every policy evaluation returns ALLOW, BLOCK, or ESCALATE. BLOCK is a hard stop --- no override, no approval path. ESCALATE pauses the action and routes it to a human. The policy author decides which is appropriate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policies are data, not code.&lt;/strong&gt; Rules are defined in YAML, not embedded into your agent logic. Changing a spending cap or tightening a file deletion policy means updating a few lines in a file, instead of touching code and redeploying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policies can be deterministic, or semantic.&lt;/strong&gt; Hard, rule-based checks like spending limits, path allowlists, per-call caps, are deterministic. For natural language rules that require reasoning and judgement, e.g. "escalate if the email tone is aggressive", semantic policies are natively supported, with evaluation done by a separate LLM you provide.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;Limenex in practice&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's look at an example. Suppose you have a research agent that can top up its own OpenAI API credits --- a common pattern in production agentic systems. Here's what the tool looks like without governance, and what changes when you wire it through Limenex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before: naive top-ups (no governance)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# BEFORE: unguarded "top up OpenAI credits" helper
&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;naive_top_up_openai&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[naive] Topped up OpenAI credits by $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;naive_scenario&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=== BEFORE: naive top-ups ===&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;naive_top_up_openai&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# looks fine
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;naive_top_up_openai&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;600.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# just as easy
&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;naive_scenario&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, there are no limits and no approval path. The agent can top up $40 or $600 without any issues. You could hardcode an &lt;code&gt;if amount_usd &amp;gt; 500&lt;/code&gt; check --- that works for one function in one service. Limenex solves this across all your agent's skills, with rules defined in YAML that anyone can change without redeploying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After: Limenex-governed top-ups&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We define two deterministic policies for &lt;code&gt;finance.spend&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;BLOCK&lt;/strong&gt; any single top-up over $500 --- a &lt;strong&gt;stateless&lt;/strong&gt; per-call check (no approval path).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESCALATE&lt;/strong&gt; when cumulative spend for this agent would exceed $100 --- a &lt;strong&gt;stateful&lt;/strong&gt; cumulative check (human review).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;finance.spend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Hard-block any single top-up over $500 — no approval path&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deterministic&lt;/span&gt;
      &lt;span class="na"&gt;dimension&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openai_single_topup_usd&lt;/span&gt;
      &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lt&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500.0&lt;/span&gt;
      &lt;span class="na"&gt;param&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amount_usd&lt;/span&gt;
      &lt;span class="na"&gt;breach_verdict&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;BLOCK&lt;/span&gt;
      &lt;span class="na"&gt;stateful&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

    &lt;span class="c1"&gt;# Escalate if cumulative spend would exceed $100 — human review&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deterministic&lt;/span&gt;
      &lt;span class="na"&gt;dimension&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openai_cumulative_spend_usd&lt;/span&gt;
      &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lt&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100.0&lt;/span&gt;
      &lt;span class="na"&gt;param&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amount_usd&lt;/span&gt;
      &lt;span class="na"&gt;breach_verdict&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ESCALATE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that policy order matters --- the engine evaluates in sequence and stops on the first non-ALLOW verdict, so hard safety rules go first.&lt;/p&gt;

&lt;p&gt;Set up the engine and create the governed skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;limenex.core.engine&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BlockedError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EscalationRequired&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PolicyEngine&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;limenex.core.policy_store&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LocalFilePolicyStore&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;limenex.core.stores&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LocalFileStateStore&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;limenex.skills.finance&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;make_spend&lt;/span&gt;

&lt;span class="c1"&gt;# Set up Limenex engine and the governed finance.spend skill
&lt;/span&gt;&lt;span class="n"&gt;policy_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalFilePolicyStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policies_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;state_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalFileStateStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limenex_dir&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;state_langgraph.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PolicyEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policy_store&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;policy_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state_store&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;state_store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Payment executor — this would be your real OpenAI billing call in production
&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;openai_top_up_executor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[governed] Approved OpenAI top-up of $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;spend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_spend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;openai_top_up_executor&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;# This is what you'd expose to your LLM agent as a tool — plain data parameters only:
# async def top_up_openai(amount_usd: float) -&amp;gt; None: ...
&lt;/span&gt;&lt;span class="n"&gt;AGENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research-agent-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;top_up_openai&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# agent_id is application-layer context, not agent input
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;spend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AGENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optionally, wrap it as a LangGraph tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;top_up_openai_credits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Top up OpenAI API credits. Governed by Limenex — subject to
    per-call and cumulative spend limits.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;spend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AGENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Topped up $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; successfully.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;BlockedError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Blocked — $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; exceeds the single transaction limit.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;EscalationRequired&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Escalated — $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; requires human approval.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pass &lt;code&gt;top_up_openai_credits&lt;/code&gt; to a &lt;code&gt;ToolNode&lt;/code&gt; and bind it to your agent's model. The agent sees a plain function with &lt;code&gt;amount_usd: float&lt;/code&gt;. Governance is invisible to the agent and to your graph definition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens at runtime&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's imagine the agent makes four calls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Top up $40 (allowed).&lt;/li&gt;
&lt;li&gt;Top up $30 (allowed, cumulative now $70).&lt;/li&gt;
&lt;li&gt;Top up $50 (would take cumulative to $120) → ESCALATE.&lt;/li&gt;
&lt;li&gt;Top up $600 (fails the single-top-up limit) → BLOCK.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Call&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;th&gt;Cumulative&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;$40&lt;/td&gt;
&lt;td&gt;$40&lt;/td&gt;
&lt;td&gt;ALLOW&lt;/td&gt;
&lt;td&gt;Under both limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;$30&lt;/td&gt;
&lt;td&gt;$70&lt;/td&gt;
&lt;td&gt;ALLOW&lt;/td&gt;
&lt;td&gt;Still under $100 cumulative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;$50&lt;/td&gt;
&lt;td&gt;would be $120&lt;/td&gt;
&lt;td&gt;ESCALATE&lt;/td&gt;
&lt;td&gt;$70 + $50 &amp;gt; $100 — routed to human&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;$600&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;BLOCK&lt;/td&gt;
&lt;td&gt;$600 &amp;gt; $500 — hard stop&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Call 3 raises &lt;code&gt;EscalationRequired&lt;/code&gt;. Your application catches it, stores the paused action, notifies a human, and re-invokes or rejects based on their decision. Call 4 never reaches the executor. A retry loop burning $3,000 hits ESCALATE at $100 and stops --- not because the agent chose to, but because the policy engine made it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;What Limenex governs&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Limenex currently ships governed skills across four categories:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Skills&lt;/th&gt;
&lt;th&gt;Example policy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Finance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;finance.charge&lt;/code&gt;, &lt;code&gt;finance.spend&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Block if single charge &amp;gt; $500; escalate if cumulative spend &amp;gt; $100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Filesystem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;filesystem.delete&lt;/code&gt;, &lt;code&gt;filesystem.write&lt;/code&gt;, &lt;code&gt;filesystem.move&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Block if filepath not in allowed directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Comms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;comms.send&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Escalate if recipient not in approved contacts; semantic check on message tone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;web.post&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block if destination not in allowlisted endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If a function is too broad to attach a clear, bounded policy to, it shouldn't be a skill. Skills are intentionally the smallest meaningful unit of consequential action. The library focuses on horizontal categories that apply across industries — domain-specific skills are best built in your own codebase using the same patterns and engine.&lt;/p&gt;




&lt;p&gt;Agentic AI is powerful — but that power needs guardrails to be safe and useful in production. Limenex is our little contribution to making that happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Get started&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;limenex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define your policies in YAML. Wire up the engine. Wrap your tool. That's it.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://github.com/limenex-hq/limenex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://limenex.dev" rel="noopener noreferrer"&gt;Quickstart guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://github.com/limenex-hq/limenex/blob/main/examples/langgraph_example.ipynb" rel="noopener noreferrer"&gt;Full LangGraph example notebook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this solves a problem you've been thinking about, star the repo — it helps other developers find it.&lt;/p&gt;




</description>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
