Metadata-Version: 2.4
Name: agentguard47
Version: 1.2.5
Summary: Zero-dependency runtime guardrails for coding agents and AI agents - stop loops, retries, and budget overruns with local traces
Author-email: BMD PAT LLC <pat@bmdpat.com>
License-Expression: MIT
Project-URL: Homepage, https://agentguard47.com
Project-URL: Documentation, https://github.com/bmdhodl/agent47#readme
Project-URL: Repository, https://github.com/bmdhodl/agent47
Project-URL: Issues, https://github.com/bmdhodl/agent47/issues
Project-URL: Changelog, https://github.com/bmdhodl/agent47/releases
Keywords: agents,coding-agents,ai-agents,multi-agent,llm,guardrails,runtime-guardrails,loop-detection,budget-guard,retry-guard,runtime-enforcement,coding-agent-safety,langchain,openai,anthropic
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: System :: Monitoring
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.1; extra == "langchain"
Provides-Extra: langgraph
Requires-Dist: langgraph>=0.1; extra == "langgraph"
Provides-Extra: crewai
Requires-Dist: crewai>=0.28; extra == "crewai"
Provides-Extra: otel
Requires-Dist: opentelemetry-api>=1.20; extra == "otel"
Requires-Dist: opentelemetry-sdk>=1.20; extra == "otel"
Dynamic: license-file

<!-- Generated by scripts/generate_pypi_readme.py. Edit README.md and CHANGELOG.md instead. -->

# 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](https://img.shields.io/pypi/v/agentguard47)](https://pypi.org/project/agentguard47/)
[![Downloads](https://img.shields.io/pypi/dm/agentguard47)](https://pypi.org/project/agentguard47/)
[![Python](https://img.shields.io/pypi/pyversions/agentguard47)](https://pypi.org/project/agentguard47/)
[![CI](https://github.com/bmdhodl/agent47/actions/workflows/ci.yml/badge.svg)](https://github.com/bmdhodl/agent47/actions/workflows/ci.yml)
[![Coverage](https://img.shields.io/badge/coverage-93%25-brightgreen)](https://github.com/bmdhodl/agent47)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/bmdhodl/agent47/blob/v1.2.5/LICENSE)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/bmdhodl/agent47/badge)](https://scorecard.dev/viewer/?uri=github.com/bmdhodl/agent47)
[![GitHub stars](https://img.shields.io/github/stars/bmdhodl/agent47?style=social)](https://github.com/bmdhodl/agent47)

```bash
pip install agentguard47
```

## Verify your install

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

```bash
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:

```bash
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:

```json
{
  "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/`](https://github.com/bmdhodl/agent47/tree/v1.2.5/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`](https://github.com/bmdhodl/agent47/blob/v1.2.5/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`](https://github.com/bmdhodl/agent47/blob/v1.2.5/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:

```bash
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:

```bash
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:

```bash
python examples/try_it_now.py
```

[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/bmdhodl/agent47/blob/v1.2.5/examples/quickstart.ipynb)

## Quickstart: Stop a Runaway Agent in 4 Lines

```python
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:

```bash
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](https://arxiv.org/abs/2401.15811))
- 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)` |

```python
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
```

```python
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

```bash
pip install agentguard47[langchain]
```

```python
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

```bash
pip install agentguard47[langgraph]
```

```python
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

```bash
pip install agentguard47[crewai]
```

```python
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

```python
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.

```python
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.

```python
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)
```

```bash
$ 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:

```bash
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.

```python
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()
)
```

```bash
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.

```yaml
# .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`](https://github.com/bmdhodl/agent47/blob/v1.2.5/docs/ci/cost-gate-workflow.yml)

## Incident Reports

Turn a trace into a postmortem-style incident summary:

```bash
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.

```python
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:

```python
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](https://github.com/bmdhodl/agent47-dashboard)).

## Security

- **Zero runtime dependencies** — one package, nothing to audit, no supply chain risk
- **[OpenSSF Scorecard](https://scorecard.dev/viewer/?uri=github.com/bmdhodl/agent47)** — 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](https://github.com/bmdhodl/agent47/blob/v1.2.5/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](https://bmdpat.com/start) | [See the research](https://bmdpat.com/research)

## License

MIT (BMD PAT LLC)

## Latest Release Notes (1.2.5)

### Distribution and Registry Hygiene
- Added official MCP Registry metadata plus package-local Docker and Smithery config for `@agentguard47/mcp-server`.
- Added `sdk/tests/test_mcp_registry_metadata.py` to keep MCP registry metadata, packaging files, and environment-variable contracts aligned.
- Refreshed README, SDK README, PyPI README, and package metadata around coding-agent safety and local-first onboarding.

### Public Repo Hygiene
- Removed stale tracked `context/` files that carried business-sensitive planning data not meant for the public SDK repo.
- Retired the obsolete `inbox/INBOX_PROTOCOL.md` workflow in favor of the current `memory/` plus `inbox/log.md` contract.

Full changelog: [CHANGELOG.md](https://github.com/bmdhodl/agent47/blob/v1.2.5/CHANGELOG.md)
