Observed since 20 Oct, 22:05 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Zero-dependency runtime control for production Python agents - stop loops, retry storms, and budget burn
Stop runaway agents with runtime checks in Python.
AgentGuard checks budgets, repeated tool calls, retries, and elapsed time in instrumented Python code. Guards raise exceptions so your application can stop the next operation. The base SDK has no runtime dependencies and needs no account.
Names: this repository is agent47, the PyPI package is agentguard47,
and the Python import is agentguard. AgentGuard 2.0.0 requires Python 3.11 or newer.
On Python 3.9 or 3.10, pin agentguard47==1.4.0. See the
Python migration guide before upgrading.
Install in a virtual environment, then run the offline checks:
python -m pip install agentguard47
agentguard doctor
agentguard demo
doctor checks the installation and local trace writing. demo exercises
budget, loop, and retry stops without provider keys or network access. Follow
the trace path printed by the command to inspect its output.
agentguard demo --feedback prints a local redacted report; nothing is sent.
For a fresh PowerShell install and a runnable raw starter, follow the published-release walkthrough.
agentguard receipt agentguard_demo_traces.jsonl prints a receipt of each stop
with the trace's SHA-256 drawn as a barcode. Add --format markdown to paste it
into a PR or issue. The hash identifies the trace file; it is not a signature.
agentguard hook claude-code --install --write
This installs a Claude Code hook that refuses the third identical tool call in
a row and a call that already failed twice. Refusals go to
.agentguard/claude-code/trace.jsonl. It checks tool calls, not tokens or
subscription quota. See the Claude Code hook guide.
agentguard run --budget-usd 5 agent.py
This patches the OpenAI and Anthropic clients, then runs agent.py in the same
interpreter. Settings come from flags, then environment variables, then
.agentguard.json. A guard stop exits 1. Every run ends with the trace path on
stderr, ready for agentguard receipt. agentguard run python -m mypkg works too. The bounds are
the same as patching the client yourself; see
enforcement boundary.
Save this as budget_demo.py and run python budget_demo.py. It makes no
network requests.
from agentguard import BudgetExceeded, BudgetGuard
budget = BudgetGuard(max_calls=2)
completed = 0
for _ in range(3):
try:
budget.check() # Check before the operation.
# Put your provider or tool call here.
completed += 1
budget.consume(calls=1) # Record the completed operation.
except BudgetExceeded:
print(f"Stopped before call {completed + 1}")
assert completed == 2
Expected output: Stopped before call 3.
Install the provider's client separately. For OpenAI:
python -m pip install openai
from agentguard import BudgetGuard, JsonlFileSink, Tracer, patch_openai
budget = BudgetGuard(max_cost_usd=5.00)
tracer = Tracer(
service="my-agent",
sink=JsonlFileSink(".agentguard/traces.jsonl"),
)
patch_openai(tracer, budget_guard=budget)
# Make your OpenAI chat.completions.create or responses.create calls after this setup.
Standard OpenAI clients created earlier are covered too, including resource
objects obtained before the patch. Activate the patch before sending requests
or saving bound methods and raw/streaming response helpers. Those saved
references can retain the original callable; recreate them after activation.
patch_openai_async() covers async clients, and agentguard.init() enables
both. See the enforcement boundary.
The patch checks recorded usage before dispatch and records response usage
afterward, including streamed calls once the final usage arrives. A response
can exceed the remaining cost or token allowance. Concurrent requests do not
reserve capacity. Chat Completions streams request include_usage unless the
caller already set it.
The OpenAI Agents SDK runs on responses.create, so agentguard.init() before
the Runner puts every model call under the budget
(example). Hosted tools and
background=True responses are not covered. See the getting started guide
for setup, traces, and framework starters.
flowchart TD
accTitle: AgentGuard operation checks
accDescr: Check a limit before an operation, then record usage.
A[Instrumented operation] --> B{Guard check}
B -->|Limit reached| C[Raise exception]
B -->|Allowed| D[Run operation]
D --> E[Record usage and trace]
E --> A
Text equivalent: check before an operation, run it if allowed, then record usage. A guard exception returns control to your application's error handler.
| Guard | Checks | Raises |
|---|---|---|
BudgetGuard | Recorded calls, tokens, or estimated cost | BudgetExceeded |
LoopGuard | Repeated tool calls | LoopDetected |
FuzzyLoopGuard | Tool frequency and alternating patterns | LoopDetected |
RetryGuard | Retries per tool | RetryLimitExceeded |
TimeoutGuard | Elapsed time when checked | TimeoutExceeded |
RateLimitGuard | Calls within a sliding minute | BudgetExceeded |
X402SpendGuard | Payment amounts before the payment callback | BudgetExceeded |
For task budgets, use BudgetGuard.goal(...). For signatures and defaults,
read the guard source and
public exports.
[crewai] extra pulls ChromaDB. The
2026-09-12 audit found four unresolved
advisories, including PYSEC-2026-311 / CVE-2026-45829.
Review that exposure before installing the extra. Base SDK installs do not
include ChromaDB.See security reporting, the dated dependency audit, and release notes. Audit results describe their recorded date, not a permanent clean bill of health.
The SDK is the free local proof path. Start local. Add hosted ingest only when you need retained history, alerts, team visibility, spend trends, hosted decision history, or dashboard-managed remote kill signals.
Local guards remain authoritative. HttpSink mirrors trace and decision events;
it does not execute remote kill signals by itself. See the
dashboard contract before configuring it.
Local use has no hosted event quota, retention period, or API-key allocation.
Network egress requires an integration you configure, such as HttpSink or
an OpenTelemetry exporter.
Nothing in the local SDK phones home. The AgentGuard website describes the optional hosted service.
| You want to | Start here |
|---|---|
| See which paths actually stop a call | Enforcement boundary |
| Install and trace a first run | Getting started |
| Find guides and source references | Documentation index |
| Try a runnable example | Examples |
| Connect LangChain, LangGraph, or CrewAI | Integration guides |
| Inspect hosted data through MCP | Read-only TypeScript MCP server |
| Use local budget tools through MCP | Python budget MCP server |
| Navigate with an AI assistant | AI documentation index |
| Contribute a fix | Contributing |
| Check what changed | Changelog |
Maintained by Patrick Hughes. Report a bug with the package version, a minimal reproduction, and the expected result. Report vulnerabilities through SECURITY.md.
The source metadata defines the branch version. The PyPI badge links to the published version. Documentation examples and local links are tested in CI. The PyPI README is generated from this README and the changelog.
This major release replaces the planned 1.4.1 patch.
agentguard47==1.4.0 on an older interpreter. See the
migration guide.agentguard receipt <trace.jsonl> prints each guard stop, the recorded
cost, and the trace's SHA-256 as a barcode. --format markdown wraps it for
PRs and issues; --format json is for CI. The receipt counts cost the same
way as report, so the call that tripped a budget is counted once.
agentguard hook claude-code is a Claude Code hook. It refuses the third
identical tool call in a row, a call that already failed twice, and, with
--max-calls, calls past a per-session cap. --install --write adds it to
.claude/settings.local.json and keeps existing hooks; --uninstall removes
only its own. Refusals are logged for agentguard receipt. See
the guide.
agentguard run [--budget-usd N] agent.py runs an unmodified script with the
OpenAI and Anthropic clients patched. Flags, environment variables, and
.agentguard.json set the limits. A guard stop exits 1. Every run ends by
printing the trace path to stderr for agentguard receipt.
patch_openai and patch_openai_async (and so agentguard.init() and
agentguard run) now cover the OpenAI Responses API: responses.create,
responses.parse, responses.stream(), and the raw and streaming response
wrappers. That puts the OpenAI Agents SDK under the budget: Runner.run and
Runner.run_streamed stop before the next model call once the budget is
spent. Store-backed guards reserve on max_output_tokens. Hosted tools,
background=True, and the WebSocket transport are not covered; see the
enforcement boundary and
examples/openai_agents_sdk_budget.py. Both are Supported in the
compatibility matrix: a separate Responses/Agents
floor job runs OpenAI 1.66.3 / Agents 0.0.3 without skips. Chat Completions
retains its separate OpenAI 1.40.0 floor.
report, incident, and summarize_trace() now calculate elapsed time
across the recorded span timeline instead of labelling the longest single
span as the whole run. Sequential gaps are included; overlapping or nested
spans are not summed. Duration-only legacy traces keep the longest-span
fallback. EvalSuite.assert_completes_within() keeps its existing contract.
Native Ollama /api/chat and /api/generate responses now contribute
prompt_eval_count and eval_count to resolve_billable_cost() and
consume_billable(), including response objects with attributes. Cached
prompt tokens are retained without adding them to the total twice. Token
budgets previously stayed at zero. This is manual accounting, not an Ollama
client patch; see the cost guide.
OpenAI clients created before patch_openai(), patch_openai_async(), or
init() now trace and enforce their budget through shared resource methods.
Previously these calls silently bypassed both. Methods and raw/streaming
helpers saved before activation still need to be recreated; see the
enforcement boundary.
One price table. estimate_cost and the patched clients now read the same
rows. Before, the patched clients billed a gpt-5.5 prompt over 272k
tokens at half its price, and priced every Claude 5 model, claude-haiku-4-5,
and the real Claude Opus 4 id (claude-opus-4-20250514) as unknown, 8x to
137x too high. Claude, OpenAI, and Gemini rows match each provider's
pricing page as of 2026-09-26. Cached-input rates for gpt-5.5, gpt-5.4,
and Gemini 2.5 were 2x to 5x too high. GPT-6, GPT-5.6, GPT-5.2, gpt-5,
gpt-4.1, o3, o4-mini, o1-pro, and Gemini 3.x were priced as unknown; they
now have rows. Gemini 3.6, 3.7, and 3.8 Flash double on 2027-01-01 as
Google has published. Retired Gemini 1.5 and 2.0 rows are removed.
Gemini thinking tokens were not billed, and Gemini cache reads were billed at
the full input rate. thoughts_token_count now bills as output, and cached
tokens are taken out of prompt_token_count, which includes them.
Dated model ids price as their base model. An unknown Anthropic or OpenAI
model is priced at that provider's highest listed rates instead of a flat
$150 per million tokens. For OpenAI that is o1-pro, $150 in and $600 out
per million, so an output-heavy call to an unknown OpenAI model can trip a
dollar budget sooner than in 1.4.0. sdk_release_guard.py --check-price-table-age,
run by the publish workflow, fails a release when any provider's prices are
more than 90 days old.
Usage that reports only total_tokens was priced at $0 for a known model.
It is now priced at the model's output rate, or the high-water rate for an
unknown model.
The LangChain callback priced on_llm_end with estimate_cost, which
returns $0 for an unknown model and ignores cache tokens, so a dollar budget
never tripped on an unknown model. It now uses the same resolver as the
patched clients: unknown models are overestimated and Anthropic cache reads
are billed. llm.end events carry source_of_cost.
Every AsyncOpenAI and AsyncAnthropic call failed with AttributeError
after agentguard.init(), because the async patches expected an
AsyncTracer. They now accept the Tracer that init() creates.
agentguard --version prints the installed version and exits 0. In 1.4.0
it exited 2, often on the first command after install.
agentguard report, summarize_trace, incident, and
EvalSuite.assert_cost_under no longer count the call that tripped a
budget twice. guard.budget_exceeded echoes that call's cost, which its
llm.result already carries. Savings baselines skip guard events too.
Reasoning and thinking tokens were billed twice: once inside output tokens,
where OpenAI and Anthropic already count them, and again on top. That
overstated cost for o-series, gpt-5, and extended-thinking calls and could
stop a dollar budget early. They now bill once, at the output rate. A price
row with reasoning_per_1m reprices only that slice.
[crewai] extra pulls
ChromaDB with unresolved advisories, including PYSEC-2026-311 /
CVE-2026-45829. Base installs do not include ChromaDB.Full changelog: CHANGELOG.md
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 2.0.0 | 6 Oct 2026 | 7 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:05 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:bf190b6e497d67c00c2e967530aa94691d6750fabd9ef0abca2ad55c571b0289