Skip to main content
Glama
README.md
# Agent Governance Gateway

**Authorization and runtime governance for AI coding agents.** Every Claude Code tool call is intercepted, classified and recorded. Codex, Cursor and Windsurf are governed only through the gateway's MCP tools; their built-in shell and file tools are not intercepted. Risky actions go to a named human, who runs them outside the agent. Everything is signed and audited.

> An AI agent having a *capability* is not the same as it having *authority*.

## What it does

- **Intercepts every tool call** (shell, file, web and MCP) via Claude Code hooks and an MCP server, and returns **allow / observe / escalate / deny** with an itemized, explainable risk score.
- **Keeps the agent unprivileged:** approved commands run in a broker outside the agent. For third-party MCP calls the sandbox can't make itself, a human approves the exact call and the agent's identical retry is allowed once.
- **Dual control:** critical actions (e.g. a command that sends `.env` out) need two approvals by different reviewers with different keys, each signed.
- **Detects intent, not just keywords** (optional, local): a small distilled classifier plus [jev-os](https://github.com/Boredem125/jev-os) zero-shot checks scan what the agent *reads* for prompt injection, sentence by sentence. On a hit, even allowlisted shell and network actions need a human.
- **Governance-as-code:** plain-language clauses ("no moving money without human review") mapped to EU AI Act / GDPR / SR 11-7 references, checked on shell commands and on MCP/WebFetch calls, with a `test` command that measures each clause before you trust it.
- **Governance records:** versioned policies with second-reviewer change control and drift protection, a signed evidence pack for auditors, oversight metrics with approval-fatigue detection, and dev/staging/prod plus data-classification rules.
- **Operations:** every tool call is audited, with secrets scrubbed from output and logs. Denials and critical actions raise alerts (local log plus an optional webhook). Per-class rate limits stop an agent that loops, and audit retention is tiered at 90 days, 1 year or 7 years.

**Design rule:** models may only *raise* scrutiny. Deterministic rules stay in charge, so a fooled model means an extra approval, never an open door.

## Results (measured, laptop CPU)

Prompt injection in what the agent reads, held-out sets (caught, false alarms):

| Set | Keyword rules (before) | jev-os checks | Shipped (jev-os OR student) |
|---|---|---|---|
| Injections in repo files (600) | 60/309, 39/291 | 86/309, 8/291 | **256/309, 14/291** |
| deepset, genuine attacks | 0/39, 0/56 | 26/39, 1/56 | **31/39, 1/56** |
| neuralchemy (942 texts) | 156/552, 3/390 | 324/552, 86/390 | **525/552, 96/390** |

- Governance on MCP/WebFetch calls: 16/20 violations caught, 0/24 benign calls flagged (frozen test set).
- Red team: 10 of 113 evasive attacks still get through, all plain-sounding instructions with no AI wording. That case is left to the authorization layer.
- AIUC-1 (the AI agent standard, July 2026 release): 5 of 51 requirements supported, 16 partial, 30 not covered, self-assessed with the gap for each ([mapping](docs/AIUC-1_MAP.md)). Most of the 30 are organizational processes a runtime tool can't supply.
- Every adoption decision used a rule written before the test run; two candidates that missed their rule were not shipped. Full numbers, method and limits: [the write-up](docs/INTENT_AWARE_AUTHORIZATION.md).

## Security of the gateway itself

CI runs Semgrep, Gitleaks, Trivy and a ZAP API scan on every push, with SARIF upload and a severity gate. Fixed along the way: an unauthenticated HTTP API that let anyone approve and run commands, an endpoint that would pull and run any Docker image, and every real 500 ZAP found. See [SECURITY.md](SECURITY.md).

## Tech

Python 3.12 · FastAPI · MCP · Claude Code hooks · ONNX Runtime · Pydantic · PyNaCl (Ed25519) · pytest (679 tests collected, 18 Oct 2026)

## Quick start

```bash
pip install -e ".[dev]"
sandbox init . --claude --mcp      # connect a folder
sandbox watch .                    # approve escalations in another terminal
```

Useful commands: `sandbox verify` (audit chains), `sandbox explain <id>`, `sandbox alerts`, `sandbox oversight`, `sandbox retention`, `sandbox export-evidence --out pack.zip`, `sandbox policy history`.

To send alerts to Slack, Teams or any collector, set `SANDBOX_ALERT_WEBHOOK` to its incoming-webhook URL.

Guided walkthrough: `python demo/call_demo.py` runs 12 scenes through the real gateway, from normal work to a poisoned README, `.env` theft stopped by dual control, governance clauses on a Stripe call, a tampered log and an evidence pack. The agent is scripted to act as if it were fooled; everything else is the real gateway. Start `jevos serve` first for the governance scene. For a live session with the real Claude Code, `python demo/live_setup.py` builds the same project with hooks connected, and `python demo/try.py preset steal-env` (or any tool call you name) sends one call through the gateway while you approve or deny it in `sandbox watch`.

Optional intent-aware layer: `pip install -e ".[semantic]"`, then `jevos serve` and `sandbox semantic enable .`

## Docs

[Write-up: intent-aware authorization](docs/INTENT_AWARE_AUTHORIZATION.md) · [Full details](docs/DETAILS.md) · [Threat model](docs/THREAT_MODEL.md) · [Governance-as-code](docs/GOVERNANCE.md) · [Evidence pack](docs/EVIDENCE.md) · [Data and environment](docs/DATA_AND_ENVIRONMENT.md) · [Compliance mapping](docs/COMPLIANCE_MAP.md) · [AIUC-1 mapping](docs/AIUC-1_MAP.md) · [Benchmarks](benchmarks/injection/README.md)

*Compliance mappings show design intent, not certification. No software is "compliant" on its own; organisations are.*

## Licence

Everything outside `ee/` is licensed under the [MIT License](LICENSE). The `ee/` directory is the home of the self-hosted control plane and is licensed under the [Elastic License 2.0](ee/LICENSE). Today it holds an early skeleton (health and readiness endpoints and a database test harness). The web UI at `ee/web/` is part of `ee/` and so is under the Elastic License 2.0 as well.

The connector (everything outside `ee/`) never imports `ee/`. The import-linter contract in `ee/.importlinter` forbids it, and CI runs it (`lint-imports --config ee/.importlinter`).

TDQS

A4/5.0

Scored across 5 tools

Disambiguation5/5

Each tool targets a distinct capability: shell execution, file access, network fetch, request status, and sandbox overview. There is no overlap in purpose, and descriptions clearly delineate boundaries.

Naming Consistency4/5

Most tools follow a verb_noun pattern (run_privileged, request_path_access, fetch_url, check_request), but sandbox_status breaks the pattern by being noun_noun. The deviation is minor and the intent remains clear.

Tool Count5/5

With 5 tools, the server is well-scoped for its purpose of gated external operations. Each tool earns its place without redundancy or excess.

Completeness5/5

The surface covers all core operations (run, file, fetch) and provides status retrieval via check_request and sandbox_status. No obvious dead ends or missing lifecycle steps for the stated escalation workflow.

Maintenance

ActivityMaintained
ResponsivenessNo issues