Quickstart¶
Install¶
AgentGuard needs Python 3.11 or later.
pip install agentguard-oss
The package is agentguard-oss; the import is agentguard. Framework adapters are
optional extras: agentguard-oss[langchain], [openai-agents], [adk], [mcp], or [all].
Try the demo¶
agentguard demo --scripted
The demo gives an agent a calculator to fix. The repository's README contains a prompt
injection asking it to steal ~/.ssh/id_rsa. AgentGuard lets it read the README, blocks
the SSH-key read and the curl exfiltration, allows the fix and a real unit test, and
asks for approval before the push to main. Nobody is there to approve in the scripted
demo, so the push is denied; add --interactive to approve or reject it in the terminal.
With Ollama and a Gemma model installed, agentguard demo runs a
live Gemma agent instead.
Guard your first tool¶
Save this as quickstart.py and run it from an empty directory:
"""AgentGuard quickstart. Run it from any directory: python quickstart.py"""
from pathlib import Path
from agentguard import Guard, GuardDenied
workspace = Path("workspace")
workspace.mkdir(exist_ok=True)
(workspace / "notes.txt").write_text("hello from the workspace\n", encoding="utf-8")
guard = Guard(
{
"version": 1,
"defaults": {"effect": "deny"},
"rules": [
{"capability": "filesystem.read", "paths": ["./workspace/**"], "effect": "allow"},
{"capability": "shell.execute", "effect": "ask"},
],
},
audit="quickstart-audit.jsonl", # Keep the audit log outside the agent's workspace.
)
@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")
@guard.tool(capability="shell.execute")
def run(cmd: str) -> str:
"""Run a shell command. Never reached here: shell asks, and no approver is set."""
raise AssertionError("unreachable")
# Give the agent only the guarded functions. Each call is checked, then audited.
print(read_file("workspace/notes.txt"), end="")
for name, arguments in [("read_file", {"path": "~/.ssh/id_rsa"}), ("run", {"cmd": "ls"})]:
try:
guard.call(name, arguments) # The same path an agent framework uses.
except GuardDenied as exc:
print(f"Denied {name}: {'; '.join(exc.decision.reasons)}")
print("Decisions:", guard.summary)
Output:
hello from the workspace
Denied read_file: Policy default: deny; Sensitive credential file access
Denied run: Policy rule 2: ask; Capability baseline: 40; Approval rejected, unavailable, insufficient, or timed out
Decisions: {'allow': 1, 'ask': 1, 'deny': 1}
Three things happened:
read_file("workspace/notes.txt")matched thefilesystem.readrule and ran.- Reading
~/.ssh/id_rsamatched no rule (default deny) and is a credential file, which is always denied. The function never ran. runis markedask. No approval provider is configured, so asking means deny.
Look at the audit log¶
agentguard verify-log --audit quickstart-audit.jsonl
agentguard logs --audit quickstart-audit.jsonl --decision deny
Every call left proposed, denied or authorized → executing → executed →
observed events, chained by SHA-256 hashes. See Audit log.
Move the policy to a file¶
version: 1
defaults:
effect: deny
rules:
- capability: filesystem.read
paths: ["./workspace/**"]
effect: allow
- capability: shell.execute
effect: ask
guard = Guard("policy.yaml", audit="agentguard.jsonl")
Check it and ask how it decides a call before running anything:
agentguard check-policy policy.yaml
agentguard explain policy.yaml shell.execute --arg cmd="git push origin main"
Next steps¶
- Register tools with any parameter names, executors and verifiers.
- Connect your framework: LangChain/LangGraph, OpenAI Agents SDK, Google ADK, MCP.
- Add a human: Approval.