Skip to main content

Zero-dependency runtime guardrails for coding agents and AI agents - stop loops, retries, and budget overruns with local traces

Project description

AgentGuard

Your coding agent just started looping through retries and shell calls. AgentGuard stops it before it burns budget.

Zero-dependency runtime guardrails for coding agents and AI agents. Set a dollar budget, cap retries, catch loops, and keep the first run fully local.

PyPI Downloads Python CI Coverage License: MIT OpenSSF Scorecard GitHub stars

pip install agentguard47

Verify your install

Before wiring a real agent, validate the local SDK path:

agentguard doctor

doctor makes no network calls. It verifies local trace writing, confirms the SDK can initialize in local-only mode, detects optional integrations already installed in your environment, and prints the smallest correct next-step snippet.

Generate a starter

When you know the stack you want to wire, print the exact starter snippet:

agentguard quickstart --framework raw
agentguard quickstart --framework openai
agentguard quickstart --framework langgraph --json

quickstart is designed for both humans and coding agents. It prints the install command, the smallest credible starter file, and the next commands to run after you validate the SDK locally.

Coding-Agent Defaults

If you want humans and coding agents to share the same safe local defaults, add a tiny .agentguard.json file to the repo:

{
  "profile": "coding-agent",
  "service": "support-agent",
  "trace_file": ".agentguard/traces.jsonl",
  "budget_usd": 5.0
}

agentguard.init(local_only=True) and agentguard doctor will pick this up automatically. Keep it local and static: no secrets, no API keys, no dashboard settings.

Every agentguard quickstart --framework ... payload also has a matching runnable file under examples/starters/. Those starter files live in the repo for copy-paste onboarding and coding-agent setup; they are not shipped inside the PyPI wheel.

For the repo-first onboarding flow, see docs/guides/coding-agents.md.

For copy-paste setup snippets tailored to Codex, Claude Code, GitHub Copilot, Cursor, and MCP-capable agents, see docs/guides/coding-agent-safety-pack.md.

MCP Server for Coding Agents

If your coding agent already uses MCP, AgentGuard also ships a published MCP server that exposes traces, alerts, usage, costs, and saved spend from the hosted read API:

npx -y @agentguard47/mcp-server

The MCP server is intentionally narrow. The SDK stays local-first and free. The MCP server and hosted dashboard only come into play after you want retained history and team-visible operational follow-through.

Try it in 60 seconds

No API keys. No dashboard. No network calls. Just run it:

pip install agentguard47
agentguard demo
AgentGuard offline demo
No API keys. No dashboard. No network calls.

1. BudgetGuard: stopping runaway spend
  warning fired at $0.84
  stopped on call 9: cost $1.08 exceeded $1.00

2. LoopGuard: stopping repeated tool calls
  stopped on repeated tool call: Loop detected ...

3. RetryGuard: stopping retry storms
  stopped retry storm: Retry limit exceeded ...

Local proof complete.

Prefer the example script instead of the CLI? This does the same local demo:

python examples/try_it_now.py

Open In Colab

Quickstart: Stop a Runaway Agent in 4 Lines

from agentguard import Tracer, BudgetGuard, patch_openai

tracer = Tracer(guards=[BudgetGuard(max_cost_usd=5.00, warn_at_pct=0.8)])
patch_openai(tracer)  # auto-tracks every OpenAI call

# Use OpenAI normally - AgentGuard tracks cost and kills the agent at $5

That's it. Every ChatCompletion call is tracked. When accumulated cost hits $4 (80%), your warning fires. At $5, BudgetExceeded is raised and the agent stops.

No config files. No dashboard required. No dependencies.

For a deterministic local proof before wiring a real agent, run:

agentguard doctor
agentguard quickstart --framework raw
agentguard demo

agentguard doctor verifies the install path. agentguard quickstart prints the copy-paste starter for your stack. agentguard demo then proves SDK-only enforcement with a realistic local run. The dashboard remains the control plane for alerts, retained history, and remote controls.

The Problem

Coding agents and other autonomous AI agents are expensive and unpredictable:

  • Cost overruns average 340% on autonomous agent tasks (source)
  • A single stuck retry or tool loop can burn through your budget in minutes
  • Existing tools (LangSmith, Langfuse, Portkey) show you the damage after it happens

AgentGuard is built to stop runaway agents mid-run, not just explain the damage later.

AgentGuard LangSmith Langfuse Portkey
Hard budget enforcement Yes No No No
Kill agent mid-run Yes No No No
Loop detection Yes No No No
Cost tracking Yes Yes Yes Yes
Zero dependencies Yes No No No
Self-hosted option Yes No Yes No
Price Free (MIT) $2.50/1k traces $59/mo $49/mo

Guards

Guards are runtime checks that raise exceptions when limits are hit. The agent stops immediately.

Guard What it stops Example
BudgetGuard Dollar/token/call overruns BudgetGuard(max_cost_usd=5.00)
LoopGuard Exact repeated tool calls LoopGuard(max_repeats=3)
FuzzyLoopGuard Similar tool calls, A-B-A-B patterns FuzzyLoopGuard(max_tool_repeats=5)
TimeoutGuard Wall-clock time limits TimeoutGuard(max_seconds=300)
RateLimitGuard Calls-per-minute throttling RateLimitGuard(max_calls_per_minute=60)
RetryGuard Retry storms on the same flaky tool RetryGuard(max_retries=3)
from agentguard import BudgetGuard, BudgetExceeded

budget = BudgetGuard(
    max_cost_usd=10.00,
    warn_at_pct=0.8,
    on_warning=lambda msg: print(f"WARNING: {msg}"),
)

# In your agent loop:
budget.consume(tokens=1500, calls=1, cost_usd=0.03)
# At 80% → warning callback fires
# At 100% → BudgetExceeded raised, agent stops
from agentguard import RetryGuard, RetryLimitExceeded, Tracer

retry_guard = RetryGuard(max_retries=3)
tracer = Tracer(guards=[retry_guard])

with tracer.trace("agent.run") as span:
    try:
        span.event("tool.retry", data={"tool_name": "search", "attempt": 1})
        span.event("tool.retry", data={"tool_name": "search", "attempt": 2})
        span.event("tool.retry", data={"tool_name": "search", "attempt": 3})
        span.event("tool.retry", data={"tool_name": "search", "attempt": 4})
    except RetryLimitExceeded:
        # Retry storm stopped
        pass

Integrations

LangChain

pip install agentguard47[langchain]
from agentguard import Tracer, BudgetGuard
from agentguard.integrations.langchain import AgentGuardCallbackHandler

tracer = Tracer(guards=[BudgetGuard(max_cost_usd=5.00)])
handler = AgentGuardCallbackHandler(
    tracer=tracer,
    budget_guard=BudgetGuard(max_cost_usd=5.00),
)

# Pass to any LangChain component
llm = ChatOpenAI(callbacks=[handler])

LangGraph

pip install agentguard47[langgraph]
from agentguard.integrations.langgraph import guarded_node

@guarded_node(tracer=tracer, budget_guard=BudgetGuard(max_cost_usd=5.00))
def research_node(state):
    return {"messages": state["messages"] + [result]}

CrewAI

pip install agentguard47[crewai]
from agentguard.integrations.crewai import AgentGuardCrewHandler

handler = AgentGuardCrewHandler(
    tracer=tracer,
    budget_guard=BudgetGuard(max_cost_usd=5.00),
)

agent = Agent(role="researcher", step_callback=handler.step_callback)

OpenAI / Anthropic Auto-Instrumentation

from agentguard import Tracer, BudgetGuard, patch_openai, patch_anthropic

tracer = Tracer(guards=[BudgetGuard(max_cost_usd=5.00)])
patch_openai(tracer)      # auto-tracks all ChatCompletion calls
patch_anthropic(tracer)   # auto-tracks all Messages calls

Cost Tracking

Built-in pricing for OpenAI, Anthropic, Google, Mistral, and Meta models. Updated monthly.

from agentguard import estimate_cost

# Single call estimate
cost = estimate_cost("gpt-4o", input_tokens=1000, output_tokens=500)
# → $0.00625

# Track across a trace — cost is auto-accumulated per span
with tracer.trace("agent.run") as span:
    span.cost.add("gpt-4o", input_tokens=1200, output_tokens=450)
    span.cost.add("claude-sonnet-4-5-20250929", input_tokens=800, output_tokens=300)
    # cost_usd included in trace end event

Tracing

Full structured tracing with zero dependencies — JSONL output, spans, events, and cost data.

from agentguard import Tracer, JsonlFileSink, BudgetGuard

tracer = Tracer(
    sink=JsonlFileSink("traces.jsonl"),
    guards=[BudgetGuard(max_cost_usd=5.00)],
)

with tracer.trace("agent.run") as span:
    span.event("reasoning", data={"thought": "search docs"})
    with span.span("tool.search", data={"query": "quantum computing"}):
        pass  # your tool logic
    span.cost.add("gpt-4o", input_tokens=1200, output_tokens=450)
$ agentguard report traces.jsonl

AgentGuard report
  Total events: 9
  Spans: 6  Events: 3
  Estimated cost: $0.01
  Savings ledger: exact 800 tokens / $0.0010, estimated 1500 tokens / $0.0075

When a run trips a guard or needs escalation, render a shareable incident report:

agentguard incident traces.jsonl
agentguard incident traces.jsonl --format html > incident.html

The incident report summarizes guard triggers, exact-vs-estimated savings, and the dashboard upgrade path for retained alerts and remote kill switch.

Evaluation

Assert properties of your traces in tests or CI.

from agentguard import EvalSuite

result = (
    EvalSuite("traces.jsonl")
    .assert_no_loops()
    .assert_budget_under(tokens=50_000)
    .assert_completes_within(seconds=30)
    .assert_total_events_under(500)
    .assert_no_budget_exceeded()
    .assert_no_errors()
    .run()
)
agentguard eval traces.jsonl --ci   # exits non-zero on failure

CI Cost Gates

Fail your CI pipeline if an agent run exceeds a cost budget. No competitor offers this.

# .github/workflows/cost-gate.yml (simplified)
- name: Run agent with budget guard
  run: |
    python3 -c "
    from agentguard import Tracer, BudgetGuard, JsonlFileSink
    tracer = Tracer(
        sink=JsonlFileSink('ci_traces.jsonl'),
        guards=[BudgetGuard(max_cost_usd=5.00)],
    )
    # ... your agent run here ...
    "

- name: Evaluate traces
  uses: bmdhodl/agent47/.github/actions/agentguard-eval@main
  with:
    trace-file: ci_traces.jsonl
    assertions: "no_errors,max_cost:5.00"

Full workflow: docs/ci/cost-gate-workflow.yml

Incident Reports

Turn a trace into a postmortem-style incident summary:

agentguard incident traces.jsonl --format markdown
agentguard incident traces.jsonl --format html > incident.html

Use this when a run hits guard.budget_warning, guard.budget_exceeded, guard.loop_detected, or a fatal error. AgentGuard will summarize the run, separate exact and estimated savings, and suggest the next control-plane step.

Async Support

Full async API mirrors the sync API.

from agentguard import AsyncTracer, BudgetGuard, patch_openai_async

tracer = AsyncTracer(guards=[BudgetGuard(max_cost_usd=5.00)])
patch_openai_async(tracer)

# All async OpenAI calls are now tracked and budget-enforced

Optional Hosted Dashboard

For teams that need retained history, alerts, and remote controls, the SDK can mirror traces to the hosted dashboard:

from agentguard import Tracer, HttpSink, BudgetGuard

tracer = Tracer(
    sink=HttpSink(
        url="https://app.agentguard47.com/api/ingest",
        api_key="ag_...",
        batch_size=20,
        flush_interval=10.0,
        compress=True,
    ),
    guards=[BudgetGuard(max_cost_usd=50.00)],
    metadata={"env": "prod"},
    sampling_rate=0.1,  # 10% of traces
)

Keep the first integration local. Add HttpSink only when you need retained history, team-visible incidents, alerts, or hosted controls.

Architecture

Your Agent Code
    │
    ▼
┌─────────────────────────────────────┐
│           Tracer / AsyncTracer       │  ← trace(), span(), event()
│  ┌───────────┐  ┌────────────────┐  │
│  │  Guards    │  │  CostTracker   │  │  ← runtime intervention
│  └───────────┘  └────────────────┘  │
└──────────┬──────────────────────────┘
           │ emit(event)
    ┌──────┼──────────┬───────────┐
    ▼      ▼          ▼           ▼
 JsonlFile  HttpSink  OtelTrace  Stdout
  Sink      (gzip,    Sink       Sink
            retry)

What's in this repo

Directory Description License
sdk/ Python SDK — guards, tracing, evaluation, integrations MIT
mcp-server/ MCP server — agents query their own traces MIT
site/ Landing page MIT

Dashboard is in a separate private repo (agent47-dashboard).

Security

  • Zero runtime dependencies — one package, nothing to audit, no supply chain risk
  • OpenSSF Scorecard — automated security analysis on every push
  • CodeQL scanning — GitHub's semantic code analysis on every PR
  • Bandit security linting — Python-specific security checks in CI

Contributing

See CONTRIBUTING.md for dev setup, test commands, and PR guidelines.

Enterprise Support

Need help governing AI agents in production? BMD Pat LLC offers:

  • $500 Async Azure Audit -- cost, reliability, and governance review. No meetings. Results in 5 business days.
  • Custom agent guardrails -- production-grade cost controls, compliance tooling, kill switches.

Start a project | See the research

License

MIT (BMD PAT LLC)

Latest Release Notes (1.2.6)

Hosted Ingest Compatibility

  • HttpSink now drops local-only kind="meta" watermark records before posting to the hosted ingest API, preventing first-batch 400s from validators that only accept trace spans and point events.
  • HttpSink now mirrors supported trace kinds into both kind and type on outbound payloads so the SDK remains compatible across hosted validators while preserving local SDK semantics.

Full changelog: CHANGELOG.md

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentguard47-1.2.6.tar.gz (125.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentguard47-1.2.6-py3-none-any.whl (67.2 kB view details)

Uploaded Python 3

File details

Details for the file agentguard47-1.2.6.tar.gz.

File metadata

  • Download URL: agentguard47-1.2.6.tar.gz
  • Upload date:
  • Size: 125.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for agentguard47-1.2.6.tar.gz
Algorithm Hash digest
SHA256 419f247caed2860330e0203f5552065e50d286140c59d337dbc249ad0ecbc1a7
MD5 f598b83261f16edcdba189a39e4bb7b7
BLAKE2b-256 934470e5a46ad2a66143305685dc12a524a260d5e6ef3fa67d14b7fc141abb3c

See more details on using hashes here.

File details

Details for the file agentguard47-1.2.6-py3-none-any.whl.

File metadata

  • Download URL: agentguard47-1.2.6-py3-none-any.whl
  • Upload date:
  • Size: 67.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for agentguard47-1.2.6-py3-none-any.whl
Algorithm Hash digest
SHA256 9feec2181dc5b51772ed69f0dbb897f1a80246a1060ac249f1b4e6d07b2f188e
MD5 c639e8a7ab108e3caa2fea332d303c69
BLAKE2b-256 13982f747a6bfba2ab0aa19cc334a9f393323aef2d76720734778045538dc58d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page