Wire this into your agent in 5 minutes
AegisAI is a chokepoint, not a framework. If your agent can make one HTTP request before it executes a tool call, it can be guarded.
Run AegisAI
No API keys required. Falls back to a mock judge and SQLite automatically, so the whole stack comes up from a clean clone.
$ git clone https://github.com/Navneet-Scaler/AegisAI$ cd AegisAI$ docker compose up# API on :8000, dashboard on :3000
Mint a key
No signup. The key is returned once, you keep it. Every call to the guard endpoint authenticates with it.
$ curl -X POST localhost:8000/v1/keys -d "{}"# { "key": "ag_live_...", "key_id": "..." }$ export AEGIS_API_KEY=ag_live_...
Score a call over curl
Before your agent executes a tool call, send it here first. The response carries the verdict, the three layer scores, and the judge's reasoning.
$ curl -X POST localhost:8000/v1/guard \-H "Authorization: Bearer $AEGIS_API_KEY" \-H "Content-Type: application/json" \-d '{"tool": "delete_customer","args": {"customer_ids": ["CUST-1002"]},"user_request": "Remove this customer","agent_id": "support-agent"}'# { "verdict": "hold", "score": 0.81, "reasoning": "..." }
Pick your integration
The guard call is the same everywhere. Only how you insert it changes.
Plain Python
The guard() call that everything else below reduces to: one HTTP request before a tool executes.
$ import os, requests$ def guard(tool_name, arguments, user_request, history):r = requests.post("http://localhost:8000/v1/guard",headers={"Authorization": f"Bearer {os.environ['AEGIS_API_KEY']}"},json={"tool": tool_name,"args": arguments,"user_request": user_request,"history": history,},)return r.json()$ verdict = guard("delete_customer", {"customer_ids": ["CUST-1002"]},"Remove this customer", [])$ if verdict["verdict"] == "block":raise RuntimeError(verdict["reasoning"])$ elif verdict["verdict"] == "hold":# surface to a human, poll /calls/{call_id} for the decision...$ else:execute_tool(...)
OpenAI function calling
Insert the guard call between the model proposing a tool call and your code executing it. Full runnable example in examples/openai-function-calling/.
$ for call in response.choices[0].message.tool_calls:args = json.loads(call.function.arguments)verdict = guard(call.function.name, args, user_request, history)if verdict["verdict"] == "block":output = {"error": f"blocked: {verdict['reasoning']}"}elif verdict["verdict"] == "hold":output = {"status": "held_for_review", "call_id": verdict["call_id"]}else:output = execute_tool(call.function.name, args)
LangChain
Wrap each StructuredTool so the guard call runs inside the tool's own func, transparent to the agent executor. Full example in examples/langchain/.
$ from langchain_core.tools import StructuredTool$ def guarded(tool_fn, tool_name, user_request):def wrapped(**kwargs):verdict = guard(tool_name, kwargs, user_request, [])if verdict["verdict"] != "allow":return f"{verdict['verdict']}: {verdict['reasoning']}"return tool_fn(**kwargs)return wrapped$ guarded_tools = [StructuredTool.from_function(func=guarded(delete_customer, "delete_customer", user_request),name="delete_customer",),# ... one per tool$ ]
MCP server
Run the bundled MCP server and every tools/call routed through it is guarded before the underlying tool runs, with no changes on the client side. Source in examples/mcp-server/.
$ export AEGIS_BASE_URL=http://localhost:8000$ export AEGIS_API_KEY=$(curl -s -X POST $AEGIS_BASE_URL/v1/keys \-H "Content-Type: application/json" -d '{}' | python3 -c \"import json,sys; print(json.load(sys.stdin)['key'])")$ uv run examples/mcp-server/server.py# speaks JSON-RPC 2.0 over stdio, same transport Claude Desktop uses
Watch it decide, live.
The dashboard streams every call as it is scored, held, and resolved.
Open the dashboard