Skip to main content

The airlock for autonomous AI agents — freeze, approve, audit.

Project description

AgentGate

The airlock for autonomous AI agents.

The second your AI agent tries to do something risky — spend money, send a message, touch private data — AgentGate freezes it mid-execution, pings a human on Discord with an interactive card, and resumes the agent the instant they tap Approve. Sensitive data is stripped on the device before the cloud LLM ever sees it. Every decision streams to a real-time audit log.

In July 2025, Replit's autonomous coding AI deleted a customer's production database. The CEO publicly apologized. AgentGate is the one line of code that would have stopped that.


Three layers of trust, one line of code

@gate(my_tool, risk="high", sensitive=True)
  1. PII never leaves the device. Tools marked sensitive=True route through a local redactor (deterministic regex by default, optional Ollama backend for semantic redaction). Names, addresses, card numbers, OTP codes — stripped on your laptop before any cloud LLM call.
  2. Risky actions wait for a human. Tools marked risk="high" freeze at the gateway. A rich card lands on Discord in ~2 seconds. One tap to Approve, Deny, or Modify Budget (reuses the modal infra to redirect the agent with a new constraint).
  3. Every action is auditable. Auto-passed reads, intercepted writes, denials, redactions, threats blocked — all streamed live to a Postgres-backed Next.js dashboard with status chips, threat banners, and side-by-side privacy proof.

Architecture diagrams live in ARCHITECTURE.md.


Four demos in one repo

Command What it shows
python -m agent.run Domain buying. APPROVAL + INPUT (CAPTCHA) + Modify Budget + real Razorpay test charge.
python -m agent.bank_run Bank login. INPUT × 2 (CAPTCHA + OTP) + sensitive × 2 (credentials + transactions). The WhatClaudeSaw dashboard panel proves PII never leaves the device.
python -m agent.injection_run Prompt-injection defense. Agent reads an article with a hidden indirect-injection, gets hijacked, tries to POST to an attacker URL. AgentGate intercepts at the tool layer; the dashboard pulses red with 🚨 THREAT BLOCKED.
python -m agent.run --unsafe The "before" shot. Runs the same agent with AgentGate disabled — no audit log row, no Discord card, raw PII goes straight to Anthropic's API, real Razorpay charge happens silently. Use to set up the contrast on stage.

Full presentation-day playbook in DEMO.md.


Repository structure

AgentGate/
├── gateway/                 FastAPI gateway + discord.py bot (one process)
│   ├── main.py              app + lifespan (bot starts in here)
│   ├── routes.py            /gate/intercept, /gate/decision, /gate/complete,
│   │                        /gate/redaction, /healthz
│   ├── pause.py             in-process asyncio.Event registry — what freezes
│   │                        the held HTTP request
│   ├── db.py                Supabase actions-table writes
│   └── discord_bot/         bot + Discord cards (Approve / Deny / Modify
│                            Budget) + INPUT-mode modal (CAPTCHA / OTP)
│
├── agentgate_sdk/           one-line tool wrapper for any LangChain agent
│   ├── langchain.py         gate(func, risk=, mode=, sensitive=, ...)
│   ├── client.py            HTTP client (long read timeout for the held call)
│   └── redactor.py          local PII redactor — regex + optional Ollama
│
├── agent/                   four demo agents (see table above)
│
├── dashboard/               Next.js 14 + Tailwind, Supabase Realtime
│   ├── app/page.tsx         live audit log
│   ├── app/pitch/page.tsx   one-page pitch + live counters
│   └── components/          HeroStats, ThreatBlocked, WhatClaudeSaw,
│                            AuditTable, StatusChip
│
├── supabase/schema.sql      actions table + realtime publication + RLS
├── tests/                   32 automated tests
├── DEMO.md                  presentation runbook for all four scenarios
├── ARCHITECTURE.md          diagrams + sequence views
├── docker-compose.yml       one-command startup
└── Dockerfile

Setting up the repo

The fastest path is docker compose up — it skips every Python and Node version issue below. Use the manual setup if you want to debug, run tests, or step through agent code with VS Code.

0 — Prerequisites

Tool Version Used by
Python 3.10+ gateway, SDK, agents, tests
Node 20.9+ (Next 16 requires it; pinned in dashboard/.nvmrc) dashboard
Supabase project free tier is fine actions table + realtime
Discord application with a bot user + a guild + a channel approval cards
Anthropic API key with Claude 4.x access agent's LLM
Razorpay test keys optional real test-mode charge in domain-buying demo
Ollama optional semantic PII redaction (fallback is a regex redactor)

1 — Clone and create the Python venv

git clone <this-repo>
cd AgentGate
python -m venv .venv

Then activate it — every command in this guide assumes the venv is active.

# macOS / Linux
source .venv/bin/activate

# Windows PowerShell
.\.venv\Scripts\Activate.ps1

# Windows cmd
.venv\Scripts\activate.bat

Your prompt should now show a (.venv) prefix. If PowerShell rejects Activate.ps1, run once: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser.

2 — Install Python dependencies

pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt   # only if you'll run pytest

Sanity check the venv: which python (Linux/mac) or (Get-Command python).Source (PowerShell) must point inside .venv/. If not, the venv isn't activated — go back to step 1.

3 — Stand up the external services

3a. Supabase

  1. Create a project at https://supabase.com.
  2. In the SQL editor, paste and run the entire contents of supabase/schema.sql. This creates the actions table, the audit_events table, the realtime publication, and the RLS policies.
  3. From Project Settings → API, copy:
    • Project URLSUPABASE_URL / NEXT_PUBLIC_SUPABASE_URL
    • anon public keyNEXT_PUBLIC_SUPABASE_ANON_KEY
    • service_role secret keySUPABASE_SERVICE_KEY

3b. Discord

  1. Create an app at https://discord.com/developers/applicationsBot → reset token → DISCORD_BOT_TOKEN.
  2. Under OAuth2 → URL Generator, scope bot, permissions Send Messages, Embed Links, Read Message History. Open the generated URL and invite the bot to a server.
  3. In Discord, enable Developer Mode (User Settings → Advanced), right-click the channel you want approval cards in → Copy Channel IDDISCORD_CHANNEL_ID.

3c. Anthropic

Get an API key at https://console.anthropic.comANTHROPIC_API_KEY.

4 — Configure environment files

Both files must point at the same Supabase project, or the dashboard will load but show nothing.

Root .env (consumed by the gateway):

cp .env.example .env

Then fill in .env with the values from step 3:

SUPABASE_URL=https://<ref>.supabase.co
SUPABASE_SERVICE_KEY=<service_role key>
NEXT_PUBLIC_SUPABASE_URL=https://<ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon key>
DISCORD_BOT_TOKEN=<bot token>
DISCORD_CHANNEL_ID=<channel id>
ANTHROPIC_API_KEY=<key>
GATE_SHARED_SECRET=<any random string>
# Razorpay + LOCAL_LLM_URL are optional

Dashboard dashboard/.env.local (consumed by Next.js, same values as the two NEXT_PUBLIC_* keys above):

NEXT_PUBLIC_SUPABASE_URL=https://<ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon key>

Heads up: Next.js reads .env.local only at startup. If you change it, restart npm run dev.

5 — Install dashboard dependencies

cd dashboard
npm install
cd ..

If npm install complains about Node version, you're on the wrong Node. See Windows gotchas below.

6 — Smoke-test the install

With the venv active:

# 1. Boot the gateway in one terminal
uvicorn gateway.main:app --port 8000

In a second terminal:

# 2. Health check — must say "supabase": true, "discord": true
curl http://localhost:8000/healthz

If supabase or discord is false, the gateway can't see your keys — re-check .env and make sure the gateway terminal has the venv activated.

# 3. Run the test suite
pytest -v

All 32 tests should pass. If they don't, your .venv probably has stale deps — pip install -r requirements.txt again.

7 — Run the full stack

Three terminals, all with the venv activated where Python is needed:

# Terminal 1 — gateway + Discord bot
uvicorn gateway.main:app --port 8000

# Terminal 2 — dashboard at http://localhost:3000
cd dashboard && npm run dev

# Terminal 3 — pick one of the four demos
python -m agent.run                # domain buying  (approval + INPUT + Modify Budget)
python -m agent.bank_run           # bank login     (PII redaction proof)
python -m agent.injection_run      # prompt injection defense
python -m agent.run --unsafe       # contrast: agent with AgentGate disabled

Open http://localhost:3000. The status chip should switch from "Connecting…" to Live. As the agent runs, rows stream in.

Docker shortcut

If you have Docker, the entire setup collapses to:

docker compose up

You still need .env and dashboard/.env.local filled in (step 4), and you still need to run the Supabase schema (step 3a) and Discord setup (step 3b). Docker just handles the Python/Node side.

Windows gotchas worth knowing

These all bit us during real onboarding — none are obvious from error messages.

  • Node keeps reverting to an old version (e.g., 18.x). Volta and nvm-windows both install a node shim. Volta's shim is first on PATH, so nvm use 20.9.0 silently does nothing — Volta resolves node to its own pinned default. Fix: either volta pin node@20.9.0 inside the repo (writes the pin into package.json, survives Git, auto-installs on first use) or remove C:\Program Files\Volta\ from PATH.
  • Gateway returns 500 on every request, but /healthz is fine. Almost always the wrong Python interpreter — uvicorn was launched against system Python (which has stale Supabase deps) instead of the project .venv. Pin VS Code to the venv: create .vscode/settings.json with "python.defaultInterpreterPath": "${workspaceFolder}/.venv/Scripts/python.exe", Developer: Reload Window, then re-launch.
  • PowerShell blocks Activate.ps1. Once: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser.
  • Dashboard shows "Connecting…" forever, no rows. dashboard/.env.local and .env are pointing at different Supabase projects. Sync the two NEXT_PUBLIC_* values, restart npm run dev — Next reads .env.local only at boot.
  • Port 8000 stuck even after killing uvicorn. Uvicorn with --reload spawns a worker child; killing the parent leaves the child holding the port. Get-Process python to find the orphan, Stop-Process -Id <pid> -Force.

SDK in 30 seconds

from agentgate_sdk import gate

def search_domain(idea: str) -> str:
    """Search available .com domains."""
    return run_real_search(idea)

def execute_purchase(domain: str, price: float) -> str:
    """Charge the user's card and register the domain."""
    return charge_and_register(domain, price)

def fetch_patient_record(patient_id: int) -> str:
    """Return raw EHR data."""
    return ehr_db.lookup(patient_id)

tools = [
    gate(search_domain, risk="low"),                          # auto-passes
    gate(execute_purchase, risk="high", mode="approval",      # human approves
         display=lambda kw: {"cost": kw["price"]}),
    gate(fetch_patient_record, risk="low", sensitive=True),   # PII redacted
]

That's it. The same gate() works with any framework that consumes LangChain tools (CrewAI, OpenAI Agents SDK, your custom orchestrator).

Policy belongs to security teams, not agent code

Drop a risk-policies.yaml at the repo root and the SDK treats that as the source of truth — security teams own risk classification via PR review, and developers just write gate(my_tool) and pick up the right policy automatically:

# risk-policies.yaml
defaults:
  risk: low
  sensitive: false
tools:
  execute_purchase:
    risk: high
    mode: approval
  read_transactions:
    risk: low
    sensitive: true     # routes through the local PII redactor
  post_to_url:
    risk: high
    mode: approval

Entries here override risk= / mode= / sensitive= passed to gate() in agent code. Override the file path via AGENTGATE_POLICY_FILE. Tools not listed fall through to whatever the developer's gate() call said.


Tests

pip install -r requirements-dev.txt
pytest -v

32 tests covering the freeze/resume registry, every gateway route (in-process via httpx.ASGITransport), the gate() wrapper paths (approve, deny, INPUT, sensitive, Modify Budget), the local redactor's pattern matrix, and one real-server integration test.


Tech stack

  • Gateway: FastAPI + Uvicorn, Python 3.10+
  • Discord: discord.py 2.x (run inside the FastAPI process — same event loop)
  • State + audit: Supabase (Postgres + Realtime)
  • Agent runtime: LangChain + langchain-anthropic, Claude Sonnet 4.6
  • Payment: Razorpay test mode (Stripe-equivalent, India-friendly)
  • PII redaction: regex by default, Ollama (local LLM) optional
  • Dashboard: Next.js 16 (App Router) + Tailwind v4
  • Deployment: Docker Compose

What this is not

  • Not a chatbot. AgentGate doesn't help if your agent's failure mode is saying something embarrassing. It catches actions, not text outputs.
  • Not a substitute for cloud-side safety. Defense in depth — the cloud LLM's safety training is one layer; AgentGate is the deterministic on-device layer.
  • Not zero-latency. The Discord round-trip is ~2 s end-to-end. Real-time HFT agents need something local-only.
  • Not built for millions of users. Per-action human approval doesn't scale to consumer apps with bulk traffic. The wedge is agentic AI in enterprise, regulated industries, and high-trust personal workflows.

License

MIT.


Built during a 3-day hackathon by Prashant Yadav, Vinay Upadhyay, and Samiksha Chhabra.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bastion_gate-1.0.0.tar.gz (25.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bastion_gate-1.0.0-py3-none-any.whl (28.2 kB view details)

Uploaded Python 3

File details

Details for the file bastion_gate-1.0.0.tar.gz.

File metadata

  • Download URL: bastion_gate-1.0.0.tar.gz
  • Upload date:
  • Size: 25.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for bastion_gate-1.0.0.tar.gz
Algorithm Hash digest
SHA256 907163baf36ad508d4fae4f0be4573d50c8e98d8aaf6d368fdff8af86f97b150
MD5 722ff57741ada77755643916b690643e
BLAKE2b-256 c3f34e5a4cb38ba08574951b45f60d8bb83458e17b75c21d8e7e931c4525e365

See more details on using hashes here.

File details

Details for the file bastion_gate-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: bastion_gate-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 28.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for bastion_gate-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0233071b9bbb763a7a0b76304780f9ef5c4abe0a33468fd8abd518d6d840d986
MD5 39bf483d3b67885055692350b3d466b4
BLAKE2b-256 34f39d121ba8ae4b7bdc048ac0cb69835ead3cbf5d550bb8a3e491097d0710bf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page