Metadata-Version: 2.4
Name: agent-autoguard
Version: 0.1.0
Summary: A real-time tool-call firewall for AI agents, built on TypeSafe's Jev.
Author: Roshan Chandna
License: MIT
Project-URL: Homepage, https://github.com/rchandnaWUSTL/auto-guard
Project-URL: Issues, https://github.com/rchandnaWUSTL/auto-guard/issues
Keywords: ai-agents,claude-code,guardrails,tool-calls,jev,typesafe
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: Security
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# Auto-Guard

**A safety check on every tool call your AI agent makes.**

Auto-Guard runs before an agent's tool call executes. It sends the proposed call and the user's request to [Jev](https://typesafe.ai), TypeSafe's fast decision model, and gets back one of three verdicts:

| Verdict | What happens |
|---|---|
| 🟢 **allow** | The call runs normally. |
| 🟡 **escalate** | You're asked to approve it, with a one-line reason written by an LLM. |
| 🔴 **block** | The call never runs. The agent is told why and picks another approach. |

A check takes about 0.4s and costs about $0.000025.

▶️ **Demo:** [what it does](https://github.com/rchandnaWUSTL/auto-guard/blob/main/demo/out/auto-guard.mp4) · [how it works](https://github.com/rchandnaWUSTL/auto-guard/blob/main/demo/out/auto-guard-under-the-hood.mp4)

---

## Quick start (Claude Code)

**1. Install**

```bash
pip install agent-autoguard
```

This needs Python 3.9+. There are no other dependencies.

**2. Add an API key.** An [OpenRouter key](https://openrouter.ai/keys) is the easiest option:

```bash
mkdir -p ~/.autoguard && echo 'OPENROUTER_API_KEY=sk-or-...' >> ~/.autoguard/env
```

**3. Turn it on** in your project. Add `--user` to turn it on for every project:

```bash
autoguard install
```

That's it. Claude Code now checks every `Bash`, `Edit`, `Write`, `MultiEdit`, `NotebookEdit` and `WebFetch` call before it runs.

To confirm it works:

```bash
autoguard check
# BLOCK      402ms  $0.000025  rm -rf /tmp/build && rm -rf ~/.aws
# ALLOW      402ms  $0.000025  ls -la build/
```

To watch decisions live, run `autoguard console` and open http://127.0.0.1:8787.

> Auto-Guard only adds restrictions. When it allows a call, Claude Code's normal permission rules still apply, and it never auto-approves anything.

---

## Use it in any agent

```python
from autoguard import guard

decision = guard("bash", "rm -rf ./build && rm -rf ~/.aws", task="clean up the build directory")

decision.action      # "block"
decision.reasons     # ["risk 3.8/4 is critical", "destructive (0.95) and outside the task (in-scope 0.18)"]
decision.rationale   # LLM-written reason (escalations only)
decision.latency_ms  # 419.1
decision.cost        # 0.0000252
```

Call `guard(tool, args, task="", plan="")` after your agent picks a tool and before it runs the tool. It works with any framework. `args` can be a string or a dict.

---

## How it decides

Each check is **one Jev request that asks five questions at once**:

| Question | Answer type | Asks |
|---|---|---|
| `destructive` | probability | Does it irreversibly delete, overwrite or leak data? |
| `in_scope` | probability | Is it what the user asked for? |
| `sensitive` | probability | Does it touch credentials, secrets, production or payments? |
| `action_class` | choice | read · local-write · network · destructive · privileged |
| `risk` | 0–4 scale | none · low · medium · high · critical |

A small policy turns the answers into a verdict:

- **Block** when risk is critical, or when the call is destructive, out of scope *and* high-risk.
- **Escalate** when risk is high, the call touches sensitive systems, the action is privileged, or Jev isn't confident.
- **Allow** everything else.

If Jev can't be reached, the call is escalated. You can change that.

---

## Configuration

**API keys.** Auto-Guard checks environment variables first. It then reads `.env.local` or `.env` files (in the current folder or any parent) and `~/.autoguard/env`.

| Variable | Get one | Used for |
|---|---|---|
| `OPENROUTER_API_KEY` | [openrouter.ai/keys](https://openrouter.ai/keys) | Jev checks + written escalation reasons |
| `TYPESAFE_API_KEY` | [console.typesafe.ai](https://console.typesafe.ai/keys) (early access) | Jev checks, direct from TypeSafe |

If both keys are set, OpenRouter is used. With only a TypeSafe key, escalations still work but come without a written reason.

**Policy.** To override any default, put a JSON file at `.autoguard.json` (per project) or `~/.autoguard/policy.json` (global):

```json
{
  "block_risk": 3.5,
  "escalate_risk": 2.5,
  "escalate_sensitive": 0.7,
  "on_error": "escalate",
  "escalation_model": "anthropic/claude-haiku-4.5",
  "spend_cap_usd": 2.5
}
```

All settings and their defaults are in [`autoguard/policy.py`](https://github.com/rchandnaWUSTL/auto-guard/blob/main/autoguard/policy.py).

**Log.** Every decision is appended to `~/.autoguard/decisions.jsonl`. To log somewhere else, set `AUTOGUARD_LOG`. Once the logged spend reaches `spend_cap_usd`, escalations stop calling the LLM.

---

## Commands

| Command | Does |
|---|---|
| `autoguard install [--user]` | Adds the Claude Code hook. Your existing settings are kept, and running it twice is safe. |
| `autoguard check` | Runs two sample calls to verify your key |
| `autoguard console` | Opens the live decision dashboard |
| `autoguard demo [block\|escalate\|all]` | Runs the scripted demo calls through the real guard |
| `autoguard eval` | Scores the policy on the labeled test calls (run it from a clone of this repo) |

---

## Results

Held-out test set of 20 calls, never used for tuning ([`evals/holdout.jsonl`](https://github.com/rchandnaWUSTL/auto-guard/blob/main/evals/holdout.jsonl)):

| | Safe allowed | Dangerous caught | Ambiguous escalated | Median latency | Cost per check |
|---|---|---|---|---|---|
| **Auto-Guard (Jev)** | **8/8** | **8/8** | **4/4** | **428ms** | **$0.000025** |
| Claude Haiku 4.5 as the guard | 8/8 | 8/8 | 3/4 | 823ms | $0.00012 |
| Claude Sonnet 5 as the guard | 7/8 | 5/8 | 1/4 | 1,992ms | $0.00032 |

On the 61-call tuning set, it allowed 26/26 safe calls and caught 25/25 dangerous ones. The thresholds were tuned on that set.

Latency was measured from a laptop via OpenRouter, with a new connection per call (the same as the Claude Code hook). Calling `guard()` repeatedly in one process reuses the connection, which brings the median to about 310–360ms.

---

## Limits

- **It's a filter, not a sandbox.** It will sometimes miss things. Keep backups, scoped credentials and sandboxing.
- **"In scope" is its weakest signal.** Jev sometimes misjudges multi-part requests. So scope only counts when the risk is also high.
- **It can block things you asked for.** "Delete my old AWS config" gets blocked because deleting credentials is high-risk. Run those commands yourself.
- **Each check adds about 0.3–0.6s.** That goes unnoticed next to an agent's own model calls, but it isn't free.

---

## Development

```bash
python3 -m unittest discover tests      # offline tests, no API calls
python3 -m autoguard eval               # re-score using cached Jev answers (free)
```

The demo videos are generated from recorded, real Jev responses. The same inputs always produce identical files:

```bash
cd demo && npm install && npm run video   # writes demo/out/*.mp4
```

```
autoguard/   guard(), policy, Jev client, Claude Code hook, CLI, live console
evals/       labeled test calls and cached Jev answers
tests/       unit tests
demo/        demo scenes, video capture (Playwright) and editing (Remotion)
```

Built on [TypeSafe's Jev](https://typesafe.ai).

## License

MIT. See [LICENSE](https://github.com/rchandnaWUSTL/auto-guard/blob/main/LICENSE).
