Local-runtime spend caps and capability-gated model routing for AI agents. Prompts, API keys, and signing keys stay inside the customer runtime. Zero data plane involvement.
Project description
agentguard-spend (Python)
Local-runtime spend caps and capability-gated model routing for AI agents.
Also available in: Español (LATAM) · Português (BR)
Python 3.10+ port of @agentguard-run/spend.
Byte-identical decision-log format and Ed25519 signing: verifiable across both
runtimes with the same public key.
Every policy decision runs inside your process. Prompts, provider API keys, and signing keys never leave your runtime. Each enforcement decision produces an Ed25519-signed, hash-chained receipt suitable for audit and compliance review.
Why no proxy
Every funded competitor in AI spend governance (Portkey, Helicone, LiteLLM,
Cloudflare AI Gateway, Vercel AI Gateway) proxies your traffic. That means your
prompts and provider keys flow through their infrastructure. agentguard-spend
never sees any of that. The policy runs in your process. The signed log lives
in your storage.
The procurement consequence: your security review covers this SDK like any other library, not like a vendor that handles your data.
Status
Private preview. Designed for enterprise, OEM, and platform integration.
For evaluation access, OEM licensing, or strategic partnership inquiries:
invest@agentguard.run
Install
pip install agentguard-spend
# Optional provider extras:
pip install "agentguard-spend[openai]"
pip install "agentguard-spend[anthropic]"
pip install "agentguard-spend[bedrock]"
# Or all of them:
pip install "agentguard-spend[all]"
Production dependency: cryptography>=42 (for Ed25519). The provider SDKs
(openai, anthropic, boto3) are peer/optional; install only what you use.
Quickstart
import asyncio
from openai import OpenAI
from agentguard_spend import (
SpendPolicy,
SpendScope,
SpendCap,
SigningKeys,
SpendGuardConfig,
InMemorySpendStore,
InMemoryDecisionLogStore,
generate_keypair,
with_spend_guard,
)
# Generate or load signing keys. They never leave your runtime.
# In production these come from your HSM / KMS / Vault.
private_key, public_key = generate_keypair() # 32-byte seed + 32-byte pubkey
policy = SpendPolicy(
id="finance-ops-v1",
name="Finance ops daily caps",
scope=SpendScope(tenantId="acme-corp"),
caps=[
SpendCap(
amountCents=500,
window="per_day",
action="downgrade",
downgradeTo="claude-sonnet-4-6",
reason="Opus daily soft cap reached, route to Sonnet",
),
SpendCap(
amountCents=1000,
window="per_day",
action="block",
reason="Hard daily ceiling",
),
],
mode="enforce",
version=1,
effectiveFrom="2026-05-23T00:00:00.000Z",
)
openai_client = OpenAI()
guarded = with_spend_guard(
openai_client,
policy=policy,
scope=SpendScope(tenantId="acme-corp", userId="alice", agentId="finance-bot"),
config=SpendGuardConfig(
policy=policy,
spendStore=InMemorySpendStore(),
logStore=InMemoryDecisionLogStore(),
signingKeys=SigningKeys(privateKey=private_key, publicKey=public_key),
),
)
# Drop-in: same API as openai.chat.completions.create
completion = guarded.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
)
When the policy fires:
| Action | Result |
|---|---|
allow |
Call passes through unchanged |
downgrade |
The model parameter is rewritten to downgradeTo, then the call proceeds |
block |
An AgentGuardBlockedError is raised before the provider is contacted |
shadow |
Call passes through; the decision is logged for analysis only |
Anthropic and Bedrock bindings
from anthropic import Anthropic
from agentguard_spend.bindings import with_anthropic_spend_guard
raw = Anthropic()
guarded = with_anthropic_spend_guard(
raw,
policy=policy,
scope=SpendScope(tenantId="acme-corp"),
)
guarded.messages.create(
model="claude-opus-4-7",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
import boto3
from agentguard_spend.bindings import with_bedrock_spend_guard
raw = boto3.client("bedrock-runtime")
guarded = with_bedrock_spend_guard(
raw,
policy=policy,
scope=SpendScope(tenantId="acme-corp"),
)
guarded.invoke_model(
modelId="anthropic.claude-sonnet-4-v1:0",
body=b'{"messages":[{"role":"user","content":"hi"}],"max_tokens":256}',
)
Capability-gated escalation
You can require a capability tier on a policy:
policy = SpendPolicy(
# ...
requiredCapability="payment_initiate",
)
Calls that do not present a capabilityClaim at or above this tier are blocked
immediately. Tiers (ascending): read_only < data_write < payment_initiate
< payment_execute.
Verifying a signed log
Anyone with the public key can verify the chain:
from agentguard_spend import verify_chain
entries = await load_entries() # from your storage
result = await verify_chain(entries, public_key)
if not result.ok:
print(f"chain invalid at sequence {result.sequence}: {result.reason}")
Each entry binds the previous entry's hash via SHA-256 and is signed with Ed25519. Tampering with any field of any entry invalidates the chain from that point forward.
Cross-language interoperability
agentguard-spend (Python) and @agentguard-run/spend (TypeScript) produce
byte-identical canonical-JSON serialization for the same SpendDecision.
That means an Ed25519 signature created in either runtime verifies in the
other. The repo includes a cross-language parity test:
- Fixture:
test_vectors/fixed_decision.json - TS reference generator:
test_vectors/compute_expected_ts.js - Python assertion:
tests/test_cross_language_parity.py
License and usage thresholds
The SDK is free for:
- Evaluation, prototyping, and non-commercial development at any volume
- Production deployments processing up to 10,000 enforcement calls per calendar month
A separate commercial license is required for:
- Production deployments processing more than 10,000 enforcement calls per month
- Deployments operated as a service to third parties
- Redistribution, sublicensing, public hosting, republication
Inbound commercial-license inquiries: invest@agentguard.run
Full terms in LICENSE. All patent rights expressly reserved (see Section 2 of
LICENSE).
Patent notice
Protected by 6 U.S. patent-pending applications:
- 63/983,615 · 63/983,621 · 63/983,843 · 63/984,626 (filed February 2026)
- 64/071,781 · 64/071,789 (filed May 21, 2026)
See LICENSE Section 7 and PATENTS.md.
Links
- agentguard.run
- Contact:
invest@agentguard.run - TypeScript SDK:
@agentguard-run/spend
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agentguard_spend-0.2.1.tar.gz.
File metadata
- Download URL: agentguard_spend-0.2.1.tar.gz
- Upload date:
- Size: 57.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f526e188ed847697d86897ad6fce44423f5f0156e8331fa98e4989245910c7e3
|
|
| MD5 |
545d2007ccfd3b13118df616da3a73a4
|
|
| BLAKE2b-256 |
4bbf6c216765f03f47f1a6ddd214394936b1620f141543b99f97e4eede764b3f
|
File details
Details for the file agentguard_spend-0.2.1-py3-none-any.whl.
File metadata
- Download URL: agentguard_spend-0.2.1-py3-none-any.whl
- Upload date:
- Size: 79.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7158cf7bb629cdcda03ba9a187095f45de1a703843a34efafcbe96f08937bd73
|
|
| MD5 |
f5eacc355a943421b2938dc93b523792
|
|
| BLAKE2b-256 |
93e5b10ea3531c074c3f509be4c559af67c5071dc181cdb12128b357def65c90
|