Metadata-Version: 2.5
Name: agentguard-oss
Version: 0.4.1
Summary: Open-source safety layer for AI agent tool calls: policy, risk checks, human approval and tamper-evident audit
Project-URL: Homepage, https://github.com/prollysamz/agentguard
Project-URL: Documentation, https://prollysamz.github.io/agentguard/
Project-URL: Repository, https://github.com/prollysamz/agentguard
Project-URL: Issues, https://github.com/prollysamz/agentguard/issues
Project-URL: Changelog, https://github.com/prollysamz/agentguard/blob/main/CHANGELOG.md
Author: Sameer Jakkuva
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,ai-safety,gemma,guardrails,llm-security,mcp,policy
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Security
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: google-re2<2,>=1.1
Requires-Dist: httpx<1,>=0.28
Requires-Dist: portalocker<4,>=3
Requires-Dist: pydantic<3,>=2.9
Requires-Dist: pyyaml<7,>=6.0.2
Provides-Extra: adk
Requires-Dist: google-adk<3,>=2; extra == 'adk'
Provides-Extra: all
Requires-Dist: google-adk<3,>=2; extra == 'all'
Requires-Dist: langchain-core<2,>=1; extra == 'all'
Requires-Dist: mcp<2,>=1.12; extra == 'all'
Requires-Dist: openai-agents<1,>=0.23; extra == 'all'
Requires-Dist: redis<9,>=5; extra == 'all'
Requires-Dist: starlette<2,>=0.40; extra == 'all'
Requires-Dist: uvicorn<1,>=0.30; extra == 'all'
Provides-Extra: dashboard
Requires-Dist: starlette<2,>=0.40; extra == 'dashboard'
Requires-Dist: uvicorn<1,>=0.30; extra == 'dashboard'
Provides-Extra: dev
Requires-Dist: bandit<2,>=1.8; extra == 'dev'
Requires-Dist: build<2,>=1; extra == 'dev'
Requires-Dist: fakeredis<3,>=2.26; extra == 'dev'
Requires-Dist: hypothesis<7,>=6.100; extra == 'dev'
Requires-Dist: langgraph<2,>=1; extra == 'dev'
Requires-Dist: pytest<10,>=8; extra == 'dev'
Requires-Dist: ruff<1,>=0.11; extra == 'dev'
Requires-Dist: twine<8,>=7; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material<10,>=9.5; extra == 'docs'
Requires-Dist: mkdocs<2,>=1.6; extra == 'docs'
Provides-Extra: langchain
Requires-Dist: langchain-core<2,>=1; extra == 'langchain'
Provides-Extra: mcp
Requires-Dist: mcp<2,>=1.12; extra == 'mcp'
Provides-Extra: openai-agents
Requires-Dist: openai-agents<1,>=0.23; extra == 'openai-agents'
Provides-Extra: redis
Requires-Dist: redis<9,>=5; extra == 'redis'
Description-Content-Type: text/markdown

# AgentGuard

**Let agents act. Keep humans in control.**

[![CI](https://github.com/prollysamz/agentguard/actions/workflows/ci.yml/badge.svg)](https://github.com/prollysamz/agentguard/actions/workflows/ci.yml)
[![Docs](https://github.com/prollysamz/agentguard/actions/workflows/docs.yml/badge.svg)](https://prollysamz.github.io/agentguard/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)

AgentGuard is an open-source Python SDK that sits between an AI agent and its tools.
Every tool call is validated, checked against a policy, scored for risk, optionally
reviewed by a local **Gemma** model, sent to a human when needed, run through a
restricted executor, verified, and written to a tamper-evident audit log.

**[Documentation](https://prollysamz.github.io/agentguard/)** ·
[Quickstart](https://prollysamz.github.io/agentguard/quickstart/) ·
[Integrations](https://prollysamz.github.io/agentguard/integrations/langchain/) ·
[Threat model](THREAT_MODEL.md) · [Changelog](CHANGELOG.md)

## See it work

```sh
pip install agentguard-oss
agentguard demo --scripted
```

An agent is asked to fix a calculator. The repository's README hides a prompt injection
telling it to read `~/.ssh/id_rsa` and upload it. AgentGuard lets the agent read the
README, **blocks** the SSH-key read and the `curl` exfiltration, **allows** the fix and a
real unit test, and **escalates** the push to `main` for human approval.

With [Ollama](https://ollama.com) and `ollama pull gemma3:4b`, plain `agentguard demo`
runs a live **Gemma agent** against the same trap, and `--judge` adds a Gemma security
reviewer. Add `--interactive` to approve the push yourself. See
[Gemma agent and judge](https://prollysamz.github.io/agentguard/gemma/).

## Guard a tool

```python
from pathlib import Path

from agentguard import Guard

guard = Guard(
    {
        "version": 1,
        "defaults": {"effect": "deny"},
        "rules": [
            {"capability": "filesystem.read", "paths": ["./workspace/**"], "effect": "allow"},
            {"capability": "shell.execute", "effect": "ask"},
        ],
    },
    audit="agentguard.jsonl",
)


@guard.tool(capability="filesystem.read")
def read_file(path: str) -> str:
    """Read a UTF-8 text file."""
    return Path(path).read_text(encoding="utf-8")


# Give the agent read_file, never the raw function.
# read_file("~/.ssh/id_rsa") raises GuardDenied before the function body runs.
```

Then check the policy, ask how it decides a call, and verify the log:

```sh
agentguard check-policy policy.yaml
agentguard explain policy.yaml shell.execute --arg cmd="git push origin main"
agentguard verify-log --audit agentguard.jsonl
```

## Use it with your framework

```sh
pip install "agentguard-oss[langchain]"   # also [openai-agents], [adk], [mcp], [all]
```

```python
from agentguard.adapters.langchain import guarded_tool        # LangChain / LangGraph
# from agentguard.adapters.openai_agents import guarded_tool  # OpenAI Agents SDK
# from agentguard.adapters.adk import guarded_tool            # Google ADK


def read_notes(path: str) -> str:
    """Read a notes file."""
    return Path(path).read_text(encoding="utf-8")


notes_tool = guarded_tool(guard, read_notes, capability="filesystem.read")
```

Denials go back to the model with AgentGuard's reasons so the agent can adapt. MCP
servers use `agentguard.adapters.mcp.register_tool`; any other loop can call
`guard.call(name, arguments)`.

## What you get

| Control | Details |
| --- | --- |
| **Policy as code** | YAML allow / ask / deny rules by capability, path, domain, environment and secrets. Explicit denies win. [Custom capabilities](https://prollysamz.github.io/agentguard/policy/#custom-capabilities) like `db.query` or `payments.refund`. |
| **Risk checks** | Explainable 0–100 scores. Credential files, destructive commands and exfiltration after a secret was seen are always denied. |
| **Human approval** | Risky calls go to a person in the dashboard, Slack or your own system without blocking the agent; grants like "allow this tool for 10 minutes". No answer means deny. |
| **Isolation** | Container executor (no network, read-only, no capabilities, optional gVisor), exact-command runners, DNS-pinned HTTPS, and an allowlisting egress proxy. |
| **Detection** | gitleaks' 221 secret rules on RE2, checksum-validated PII, and shell-aware command analysis. |
| **Verification** | Before/after hashes catch tools that change files they were not asked to. |
| **Audit** | Every stage of every call in a signed SHA-256 hash chain with rotation, exported to OpenTelemetry or a SIEM. |
| **Dashboard** | Approval queue, audit log viewer and a dry-run policy report. |
| **Multi-agent** | Parallel per-agent sessions; rate limits per session, agent or globally through Redis. |
| **Gemma** | A local Gemma agent for the demo, and an optional judge that can only add caution. |

Starter policies for [coding, browsing and support agents](examples/policies/) are in
`examples/policies/`.

## Operate it

```sh
pip install "agentguard-oss[dashboard]"
agentguard approvers add alice            # prints a token for the dashboard and API
agentguard dashboard                      # http://127.0.0.1:8765
```

```python
from agentguard.approval import ApprovalStore, QueueApproval

guard = Guard("policy.yaml", approval=QueueApproval(ApprovalStore("agentguard-approvals.db")))
```

Risky calls raise `ApprovalPending` immediately instead of blocking; the agent retries after
a human approves in the [dashboard](https://prollysamz.github.io/agentguard/dashboard/), in
Slack, or through the API. Run a new agent with `mode="dry-run"` and check
`agentguard report --dry-run-only` to tune the policy before enforcing it.

## Status

AgentGuard 0.4 is alpha and has not had an independent security audit; see the
[security review guide](https://prollysamz.github.io/agentguard/security-review/) and
[benchmarks](https://prollysamz.github.io/agentguard/benchmarks/). It is an
interception layer for cooperative applications, not an OS sandbox: an agent that also has
unguarded tools, a raw shell or Python `exec` can go around it. Read the
[threat model](THREAT_MODEL.md) before guarding privileged tools, and report
vulnerabilities privately as described in [SECURITY.md](SECURITY.md).

## Develop

```sh
git clone https://github.com/prollysamz/agentguard.git
cd agentguard
python -m venv .venv
# Windows: .venv\Scripts\activate    macOS/Linux: source .venv/bin/activate
python -m pip install -e ".[dev,all,docs]"
python -m pytest -q
python -m ruff check .
mkdocs serve
```

CI runs the tests on Linux and Windows with Python 3.11 and 3.12. See
[CONTRIBUTING.md](CONTRIBUTING.md). MIT licensed.
