Skip to main content

agentguard

PyPI version Python versions License: MIT CI

Lightweight agentic loop detector and safety monitor. Zero required dependencies.

The problem

LLM agents get stuck. A loop, a dangerous command, a runaway budget, and your agent keeps going. Existing guardrail frameworks are heavy, opinionated, and require you to rewrite your agent around them.

agentguard is different: one method call, drop-in anywhere, no LLM required.

Quick start

pip install nakata-agentguard
from agentguard import AgentGuard, Action

guard = AgentGuard()

# In your tool execution loop:
report = guard.record("bash", {"cmd": "git status"})
if report.action == Action.HALT:
    raise RuntimeError(report.reason)

What it catches

Loop detection (5 modes)

from agentguard import AgentGuard, GuardConfig

guard = AgentGuard(GuardConfig(exact_threshold=3))

# Exact: same (tool, args) repeated N times
for _ in range(3):
    guard.record("bash", {"cmd": "git status"})
# report.action == Action.HALT, "loop detected ('bash:...' called 3x)"

# Also catches:
# Near-duplicate: args differ only in whitespace/numbers
# Error-loop: tool returning errors repeatedly
# Pattern: ABCABC repeating sequence
# Stall: same tool called N times with any args

Dangerous pattern detection (110+ patterns)

No LLM required, pure regex across 9 categories:

Category Examples
DESTRUCTIVE rm -rf, DROP TABLE, docker system prune, terraform destroy
DATA_WIPE dd if=, mkfs, > /dev/sda
PRIVILEGE_ESCALATION sudo, chmod 777, docker run --privileged, nsenter
EXFILTRATION reverse shells, curl -d, /dev/tcp/, Metasploit payloads
CODE_INJECTION eval $(), shell=True, pickle.loads, curl | bash, SQL injection
SECRETS SSH keys, AWS/GCloud creds, OpenAI keys, Stripe live keys, kubeconfig
NETWORK nmap, masscan, ettercap, C2 frameworks, crypto miners
DESTRUCTIVE (cloud) aws s3 rm --recursive, gcloud ... delete, kubectl delete --all
DESTRUCTIVE (git) git push --force, git reset --hard, git filter-branch
report = guard.record("bash", {"cmd": "rm -rf /"})
# report.action    == Action.HALT
# report.dangers[0].category == DangerCategory.DESTRUCTIVE
# report.dangers[0].severity == 10

Budget monitoring

guard = AgentGuard(GuardConfig(token_limit=100_000, cost_limit_usd=5.0))
report = guard.record("llm", {"prompt": "..."}, tokens=1500, cost_usd=0.002)
# report.budget.token_pct   → 0.015
# report.budget.is_warning  → False (< 80%)
# report.budget.is_exceeded → False

Output monitoring

Catches the "464MB cat" class of bugs, tool output that is too large, binary, or stuck in a repeated-line loop.

guard = AgentGuard(GuardConfig(output_max_bytes=512_000, output_warn_bytes=100_000))
report = guard.record("bash", {"cmd": "cat bigfile"}, output="A" * 600_000)
# report.action == Action.HALT

Rate limiting

guard = AgentGuard(GuardConfig(rate_halt_cps=25.0, rate_warn_cps=10.0))
# 26 calls/second → Action.HALT

Configuration

from agentguard import AgentGuard, GuardConfig

guard = AgentGuard(GuardConfig(
    # Loop
    exact_threshold=3,
    stall_threshold=5,
    halt_on_loop=True,
    # Danger
    halt_on_severity=9,
    warn_on_severity=6,
    # Budget
    token_limit=50_000,
    cost_limit_usd=2.0,
    # Rate
    rate_halt_cps=25.0,
    rate_warn_cps=10.0,
    # Custom rules file (TOML or JSON)
    rules_file="agentguard.toml",
))

Config file

Generate a starter config:

agentguard init                     # creates agentguard.toml
agentguard init --output my.toml    # custom path
# agentguard.toml
[guard]
halt_on_severity = 9
warn_on_severity = 6
token_limit      = 100000

[[patterns]]
pattern     = "my_internal_secret_func"
category    = "secrets"
severity    = 8
description = "internal secret function"

[[allowlist]]
tool    = "bash"
pattern = "ls\\s+-la"
reason  = "safe directory listing"

Load it:

guard = AgentGuard(GuardConfig(rules_file="agentguard.toml"))

Allowlist

Skip danger checks for known-safe patterns:

from agentguard import AgentGuard, GuardConfig
from agentguard.allowlist import Allowlist

guard = AgentGuard(GuardConfig(
    allowlist=Allowlist.from_list([
        {"tool": "bash", "pattern": r"ls\s+-la", "reason": "safe listing"},
    ])
))

CLI commands

# Start stateful daemon (enables loop detection across calls)
agentguard serve --port 7420 --halt-severity 9 --token-limit 100000
agentguard serve --webhook-url https://hooks.example.com/alert  # POST on halt/warn

# Check status / reset session
agentguard status
agentguard reset

# One-shot explain (diagnostic output)
agentguard explain bash '{"cmd": "rm -rf /"}'
agentguard explain bash '{"cmd": "sudo apt update"}'

# Analyse a saved session
agentguard audit session.json

# Generate config file
agentguard init

# Claude Code hooks (PreToolUse + PostToolUse)
agentguard hooks                    # print JSON
agentguard hooks --install          # write to ~/.claude/hooks.json

Metis integration

agentguard's check command is designed as a Metis PostToolUse hook.

agentguard hooks --install   # one-time setup

Or add to ~/.metis/hooks.toml manually:

[[hooks]]
event      = "SessionStart"
command    = "agentguard serve --port 7420"
background = true

[[hooks]]
event   = "PreToolUse"
command = "agentguard check"

[[hooks]]
event   = "PostToolUse"
command = "agentguard check"

The daemon maintains session state across calls, enabling loop detection. Without the daemon, agentguard check runs stateless (danger + budget only).

HTTP daemon

pip install "nakata-agentguard[serve]"
agentguard serve --port 7420
# Record a tool call
curl -s -X POST http://localhost:7420/record \
  -H 'Content-Type: application/json' \
  -d '{"tool":"bash","args":{"cmd":"ls -la"}}'

# Status
curl http://localhost:7420/status

# Multi-session
curl http://localhost:7420/status?session=agent-1

# Prometheus metrics
curl http://localhost:7420/metrics

# Health
curl http://localhost:7420/health

# Reset
curl -X POST http://localhost:7420/reset
curl -X POST "http://localhost:7420/reset?session=all"

Webhook

agentguard serve --webhook-url https://hooks.example.com/agentguard

The daemon POSTs {"action":"halt","reason":"...","session":"default","ts":1234567890} to the URL on every halt or warn event. Webhook failures never block the agent.

Prometheus metrics

GET /metrics returns Prometheus text exposition:

agentguard_uptime_seconds 42.1
agentguard_active_sessions 3
agentguard_records_total 158
agentguard_tool_calls_total 158
agentguard_loop_events_total 2
agentguard_danger_events_total 4
agentguard_total_tokens 45200
agentguard_total_cost_usd 0.091

Session snapshot

# Save
guard.save("session.json")

# Load and audit
guard2 = AgentGuard.load("session.json")
print(guard2.stats())

# CLI audit
# agentguard audit session.json

nakata cluster

agentguard is part of the nakata AI reliability cluster:

  • halluguard, reverse-RAG hallucination detector
  • adaptmem, domain-adapted retrieval memory
  • claimcheck, end-to-end claim verification pipeline
  • agentguard, agentic loop and safety monitor

License

MIT

Release files for nakata-agentguard 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nakata-agentguard 0.4.0
File Size Uploaded
nakata_agentguard-0.4.0.tar.gz 38.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nakata-agentguard 0.4.0
File Interpreter ABI Platform
nakata_agentguard-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 70.0 kB

Release files / nakata_agentguard-0.4.0.tar.gz

Download URL nakata_agentguard-0.4.0.tar.gz
Size 38.4 kB
Tags Source
SHA-256 checksum
How to use checksums
5887ca0dc072388b030eeea09cfd54212a3bf5105aaecc8a33799500b6ad7f96
BLAKE2b-256 checksum
How to use checksums
253ad62f727ea0c82c7e1905121baa9c9f84683a98cb6a5621c3d890c20fc611
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / nakata_agentguard-0.4.0-py3-none-any.whl

Download URL nakata_agentguard-0.4.0-py3-none-any.whl
Size 31.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
79513a1e0b6618f8b711ac68dae3f777d61aad9ac5da60cfe73984c2a447340a
BLAKE2b-256 checksum
How to use checksums
7ac20cf6ccc9e6fd8b007ba35f75cb6f201b1a7458273b428eeb199a9ea3f2dd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page